summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorBenjamin Shockley <benjaminshockley@hotmail.com>2020-08-20 13:48:15 -0500
committerGitHub <noreply@github.com>2020-08-20 13:48:15 -0500
commit0084f0af24e4e219bc040c52ee723959423de6e2 (patch)
tree1aebdb362f08bf6417caa87836e3e4e739afc964 /py
parent9aebe2f1efc99871fcf283c304e3a8700050d736 (diff)
parent4d7b9cde33934a44c4c905a49d2f831339fc8bd2 (diff)
Merge pull request #2 from adafruit/master
Master
Diffstat (limited to 'py')
-rw-r--r--py/argcheck.c13
-rw-r--r--py/binary.c31
-rw-r--r--py/builtin.h7
-rw-r--r--py/builtinhelp.c4
-rw-r--r--py/builtinimport.c30
-rw-r--r--py/circuitpy_defns.mk504
-rw-r--r--py/circuitpy_mpconfig.h768
-rw-r--r--py/circuitpy_mpconfig.mk237
-rw-r--r--py/compile.c32
-rw-r--r--py/emitglue.c7
-rw-r--r--py/emitnative.c19
-rwxr-xr-xpy/gc.c173
-rw-r--r--py/gc.h19
-rwxr-xr-xpy/gc_long_lived.c8
-rw-r--r--py/lexer.c166
-rw-r--r--py/lexer.h16
-rw-r--r--py/makemoduledefs.py107
-rw-r--r--py/makeqstrdata.py90
-rw-r--r--py/map.c4
-rw-r--r--py/mkrules.mk10
-rw-r--r--py/modbuiltins.c15
-rw-r--r--py/modio.c10
-rw-r--r--py/modstruct.c16
-rw-r--r--py/moduerrno.c7
-rwxr-xr-xpy/mpconfig.h43
-rw-r--r--py/mpstate.c3
-rw-r--r--py/mpstate.h4
-rw-r--r--py/nlr.h56
-rw-r--r--py/nlrthumb.c16
-rw-r--r--py/nlrx64.c2
-rw-r--r--py/nlrx86.c2
-rw-r--r--py/nlrxtensa.c2
-rw-r--r--py/obj.c50
-rw-r--r--py/obj.h25
-rw-r--r--py/objarray.c56
-rw-r--r--py/objbool.c4
-rw-r--r--py/objcomplex.c4
-rw-r--r--py/objdeque.c4
-rw-r--r--py/objdict.c20
-rw-r--r--py/objenumerate.c6
-rw-r--r--py/objexcept.c41
-rw-r--r--py/objfilter.c4
-rw-r--r--py/objfloat.c4
-rw-r--r--py/objfun.c18
-rw-r--r--py/objint.c110
-rw-r--r--py/objint.h6
-rw-r--r--py/objlist.c54
-rw-r--r--py/objmap.c4
-rw-r--r--py/objmodule.c42
-rw-r--r--py/objnamedtuple.c13
-rw-r--r--py/objnamedtuple.h2
-rw-r--r--py/objobject.c4
-rw-r--r--py/objproperty.c4
-rw-r--r--py/objrange.c4
-rw-r--r--py/objreversed.c4
-rw-r--r--py/objset.c8
-rw-r--r--py/objslice.c71
-rw-r--r--py/objstr.c64
-rw-r--r--py/objstr.h7
-rw-r--r--py/objstringio.c6
-rw-r--r--py/objstrunicode.c20
-rw-r--r--py/objtuple.c16
-rw-r--r--py/objtype.c131
-rw-r--r--py/objtype.h4
-rw-r--r--py/objzip.c4
-rw-r--r--py/parse.c64
-rw-r--r--py/persistentcode.c28
-rw-r--r--py/proto.c50
-rw-r--r--py/proto.h42
-rw-r--r--py/py.mk56
-rwxr-xr-xpy/qstr.c4
-rw-r--r--py/repl.c9
-rw-r--r--py/ringbuf.c115
-rw-r--r--py/ringbuf.h52
-rw-r--r--py/runtime.c78
-rw-r--r--py/runtime.h19
-rw-r--r--py/sequence.c14
-rw-r--r--py/showbc.c2
-rw-r--r--py/stackctrl.c4
-rw-r--r--py/stream.c29
-rw-r--r--py/stream.h6
-rw-r--r--py/vm.c6
-rw-r--r--py/vmentrytable.h8
-rw-r--r--py/vstr.c3
84 files changed, 3357 insertions, 467 deletions
diff --git a/py/argcheck.c b/py/argcheck.c
index 5cc18d6a2..a8df206e2 100644
--- a/py/argcheck.c
+++ b/py/argcheck.c
@@ -31,13 +31,22 @@
#include "supervisor/shared/translate.h"
-void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) {
+
+void mp_arg_check_num(size_t n_args, mp_map_t *kw_args, size_t n_args_min, size_t n_args_max, bool takes_kw) {
+ size_t n_kw = 0;
+ if (kw_args != NULL) {
+ n_kw = kw_args->used;
+ }
+ mp_arg_check_num_kw_array(n_args, n_kw, n_args_min, n_args_max, takes_kw);
+}
+
+void mp_arg_check_num_kw_array(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) {
// NOTE(tannewt): This prevents this function from being optimized away.
// Without it, functions can crash when reading invalid args.
__asm volatile ("");
// TODO maybe take the function name as an argument so we can print nicer error messages
- if (n_kw && !takes_kw) {
+ if (n_kw > 0 && !takes_kw) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch();
#else
diff --git a/py/binary.c b/py/binary.c
index ca851c936..2ec12fa93 100644
--- a/py/binary.c
+++ b/py/binary.c
@@ -49,7 +49,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
switch (struct_type) {
case '<': case '>':
switch (val_type) {
- case 'b': case 'B':
+ case 'b': case 'B': case 'x':
size = 1; break;
case 'h': case 'H':
size = 2; break;
@@ -79,7 +79,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
// particular (or any) ABI.
switch (val_type) {
case BYTEARRAY_TYPECODE:
- case 'b': case 'B':
+ case 'b': case 'B': case 'x':
align = size = 1; break;
case 'h': case 'H':
align = alignof(short);
@@ -126,6 +126,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
break;
case BYTEARRAY_TYPECODE:
case 'B':
+ case 'x': // value will be discarded
val = ((unsigned char*)p)[index];
break;
case 'h':
@@ -183,7 +184,7 @@ long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, con
val = -1;
}
for (uint i = 0; i < size; i++) {
- val <<= 8;
+ val *= 256;
val |= *src;
src += delta;
}
@@ -303,15 +304,20 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
break;
}
#endif
- default:
+ default: {
+ bool signed_type = is_signed(val_type);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
+ // It's a longint.
+ mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
return;
} else
#endif
{
val = mp_obj_get_int(val_in);
+ // Small int checking is separate, to be fast.
+ mp_small_int_buffer_overflow_check(val, size, signed_type);
// 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;
@@ -321,6 +327,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
}
}
}
+ }
}
mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
@@ -342,16 +349,24 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
((mp_obj_t*)p)[index] = val_in;
break;
#endif
- default:
+ default: {
+ size_t size = mp_binary_get_size('@', typecode, NULL);
+ bool signed_type = is_signed(typecode);
+
#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);
+ // It's a long int.
+ mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
size, (uint8_t*)p + index * size);
return;
}
#endif
- mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
+ mp_int_t val = mp_obj_get_int(val_in);
+ // Small int checking is separate, to be fast.
+ mp_small_int_buffer_overflow_check(val, size, signed_type);
+ mp_binary_set_val_array_from_int(typecode, p, index, val);
+ }
}
}
@@ -364,6 +379,8 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, m
case 'B':
((unsigned char*)p)[index] = val;
break;
+ case 'x':
+ ((unsigned char*)p)[index] = 0;
case 'h':
((short*)p)[index] = val;
break;
diff --git a/py/builtin.h b/py/builtin.h
index 84b99a8a4..6e0d5d9be 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -117,6 +117,13 @@ extern const mp_obj_module_t mp_module_websocket;
extern const mp_obj_module_t mp_module_webrepl;
extern const mp_obj_module_t mp_module_framebuf;
extern const mp_obj_module_t mp_module_btree;
+extern const mp_obj_module_t ulab_user_cmodule;
+extern mp_obj_module_t ulab_fft_module;
+extern mp_obj_module_t ulab_filter_module;
+extern mp_obj_module_t ulab_linalg_module;
+extern mp_obj_module_t ulab_numerical_module;
+extern mp_obj_module_t ulab_poly_module;
+
extern const char MICROPY_PY_BUILTINS_HELP_TEXT[];
diff --git a/py/builtinhelp.c b/py/builtinhelp.c
index 9a3407a16..01c0bc84e 100644
--- a/py/builtinhelp.c
+++ b/py/builtinhelp.c
@@ -135,7 +135,7 @@ STATIC void mp_help_print_modules(void) {
// let the user know there may be other modules available from the filesystem
const compressed_string_t* compressed = translate("Plus any modules on the filesystem\n");
- char decompressed[compressed->length];
+ char decompressed[decompress_length(compressed)];
decompress(compressed, decompressed);
mp_print_str(MP_PYTHON_PRINTER, decompressed);
}
@@ -181,7 +181,7 @@ STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) {
// print a general help message. Translate only works on single strings on one line.
const compressed_string_t* compressed =
translate("Welcome to Adafruit CircuitPython %s!\n\nPlease visit learn.adafruit.com/category/circuitpython for project guides.\n\nTo list built-in modules please do `help(\"modules\")`.\n");
- char decompressed[compressed->length];
+ char decompressed[decompress_length(compressed)];
decompress(compressed, decompressed);
mp_printf(MP_PYTHON_PRINTER, decompressed, MICROPY_GIT_TAG);
} else {
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 6ed0a7594..2be779c6c 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -400,21 +400,31 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));
if (stat == MP_IMPORT_STAT_NO_EXIST) {
- #if MICROPY_MODULE_WEAK_LINKS
- // check if there is a weak link to this module
- if (i == mod_len) {
- mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP);
+ // This is just the module name after the previous .
+ qstr current_module_name = qstr_from_strn(mod_str + last, i - last);
+ mp_map_elem_t *el = NULL;
+ if (outer_module_obj == MP_OBJ_NULL) {
+ el = mp_map_lookup((mp_map_t*)&mp_builtin_module_map,
+ MP_OBJ_NEW_QSTR(current_module_name),
+ MP_MAP_LOOKUP);
+ #if MICROPY_MODULE_WEAK_LINKS
+ // check if there is a weak link to this module
if (el == NULL) {
- goto no_exist;
+ el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map,
+ MP_OBJ_NEW_QSTR(current_module_name),
+ MP_MAP_LOOKUP);
}
- // found weak linked module
+ #endif
+ } else {
+ el = mp_map_lookup(&((mp_obj_module_t*) outer_module_obj)->globals->map,
+ MP_OBJ_NEW_QSTR(current_module_name),
+ MP_MAP_LOOKUP);
+ }
+
+ if (el != NULL && MP_OBJ_IS_TYPE(el->value, &mp_type_module)) {
module_obj = el->value;
mp_module_call_init(mod_name, module_obj);
} else {
- no_exist:
- #else
- {
- #endif
// couldn't find the file, so fail
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_ImportError(translate("module not found"));
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
new file mode 100644
index 000000000..67fbde6e4
--- /dev/null
+++ b/py/circuitpy_defns.mk
@@ -0,0 +1,504 @@
+# This file is part of the MicroPython project, http://micropython.org/
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2019 Dan Halbert for Adafruit Industries
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Common Makefile definitions that can be shared across CircuitPython ports.
+
+###
+# Common compile warnings.
+
+BASE_CFLAGS = \
+ -fsingle-precision-constant \
+ -fno-strict-aliasing \
+ -Wdouble-promotion \
+ -Wno-endif-labels \
+ -Wstrict-prototypes \
+ -Werror-implicit-function-declaration \
+ -Wfloat-equal \
+ -Wundef \
+ -Wshadow \
+ -Wwrite-strings \
+ -Wsign-compare \
+ -Wmissing-format-attribute \
+ -Wno-deprecated-declarations \
+ -Wnested-externs \
+ -Wunreachable-code \
+ -Wcast-align \
+ -Wno-error=lto-type-mismatch \
+ -D__$(CHIP_VARIANT)__ \
+ -ffunction-sections \
+ -fdata-sections \
+ -DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
+ -DCIRCUITPY_CANARY_WORD=0xADAF00 \
+ -DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
+ --param max-inline-insns-single=500
+
+# Use these flags to debug build times and header includes.
+# -ftime-report
+# -H
+
+
+###
+# Handle frozen modules.
+
+ifneq ($(FROZEN_DIR),)
+# To use frozen source modules, put your .py files in a subdirectory (eg scripts/)
+# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch).
+CFLAGS += -DMICROPY_MODULE_FROZEN_STR
+CFLAGS += -Wno-error=lto-type-mismatch
+endif
+
+# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
+# then invoke make with FROZEN_MPY_DIR=frozen or FROZEN_MPY_DIRS="dir1 dir2"
+# (be sure to build from scratch).
+
+ifneq ($(FROZEN_MPY_DIRS),)
+CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
+CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
+CFLAGS += -Wno-error=lto-type-mismatch
+endif
+
+
+###
+# Propagate longint choice from .mk to C. There's no easy string comparison
+# in cpp conditionals, so we #define separate names for each.
+ifeq ($(LONGINT_IMPL),NONE)
+CFLAGS += -DLONGINT_IMPL_NONE
+endif
+
+ifeq ($(LONGINT_IMPL),MPZ)
+CFLAGS += -DLONGINT_IMPL_MPZ
+endif
+
+ifeq ($(LONGINT_IMPL),LONGLONG)
+CFLAGS += -DLONGINT_IMPL_LONGLONG
+endif
+
+
+###
+# Select which builtin modules to compile and include.
+
+ifeq ($(CIRCUITPY_AESIO),1)
+SRC_PATTERNS += aesio/%
+endif
+ifeq ($(CIRCUITPY_ANALOGIO),1)
+SRC_PATTERNS += analogio/%
+endif
+ifeq ($(CIRCUITPY_AUDIOBUSIO),1)
+SRC_PATTERNS += audiobusio/%
+endif
+ifeq ($(CIRCUITPY_AUDIOIO),1)
+SRC_PATTERNS += audioio/%
+endif
+ifeq ($(CIRCUITPY_AUDIOPWMIO),1)
+SRC_PATTERNS += audiopwmio/%
+endif
+ifeq ($(CIRCUITPY_AUDIOCORE),1)
+SRC_PATTERNS += audiocore/%
+endif
+ifeq ($(CIRCUITPY_AUDIOMIXER),1)
+SRC_PATTERNS += audiomixer/%
+endif
+ifeq ($(CIRCUITPY_AUDIOMP3),1)
+SRC_PATTERNS += audiomp3/%
+endif
+ifeq ($(CIRCUITPY_BITBANGIO),1)
+SRC_PATTERNS += bitbangio/%
+endif
+# Some builds need bitbang SPI for the dotstar but don't make bitbangio available so include it separately.
+ifeq ($(CIRCUITPY_BITBANG_APA102),1)
+SRC_PATTERNS += bitbangio/SPI%
+endif
+ifeq ($(CIRCUITPY_BLEIO),1)
+SRC_PATTERNS += _bleio/%
+endif
+ifeq ($(CIRCUITPY_BOARD),1)
+SRC_PATTERNS += board/%
+endif
+ifeq ($(CIRCUITPY_BUSIO),1)
+SRC_PATTERNS += busio/% bitbangio/OneWire.%
+endif
+ifeq ($(CIRCUITPY_COUNTIO),1)
+SRC_PATTERNS += countio/%
+endif
+ifeq ($(CIRCUITPY_DIGITALIO),1)
+SRC_PATTERNS += digitalio/%
+endif
+ifeq ($(CIRCUITPY_DISPLAYIO),1)
+SRC_PATTERNS += displayio/% terminalio/% fontio/%
+endif
+ifeq ($(CIRCUITPY_VECTORIO),1)
+SRC_PATTERNS += vectorio/%
+endif
+ifeq ($(CIRCUITPY_FRAMEBUFFERIO),1)
+SRC_PATTERNS += framebufferio/%
+endif
+ifeq ($(CIRCUITPY_FREQUENCYIO),1)
+SRC_PATTERNS += frequencyio/%
+endif
+ifeq ($(CIRCUITPY_GAMEPAD),1)
+SRC_PATTERNS += gamepad/%
+endif
+ifeq ($(CIRCUITPY_GAMEPADSHIFT),1)
+SRC_PATTERNS += gamepadshift/%
+endif
+ifeq ($(CIRCUITPY_I2CSLAVE),1)
+SRC_PATTERNS += i2cslave/%
+endif
+ifeq ($(CIRCUITPY_MATH),1)
+SRC_PATTERNS += math/%
+endif
+ifeq ($(CIRCUITPY__EVE),1)
+SRC_PATTERNS += _eve/%
+endif
+ifeq ($(CIRCUITPY_MICROCONTROLLER),1)
+SRC_PATTERNS += microcontroller/%
+endif
+ifeq ($(CIRCUITPY_NEOPIXEL_WRITE),1)
+SRC_PATTERNS += neopixel_write/%
+endif
+ifeq ($(CIRCUITPY_NETWORK),1)
+SRC_PATTERNS += network/% socket/%
+endif
+ifeq ($(CIRCUITPY_NVM),1)
+SRC_PATTERNS += nvm/%
+endif
+ifeq ($(CIRCUITPY_OS),1)
+SRC_PATTERNS += os/%
+endif
+ifeq ($(CIRCUITPY_PIXELBUF),1)
+SRC_PATTERNS += _pixelbuf/%
+endif
+ifeq ($(CIRCUITPY_RGBMATRIX),1)
+SRC_PATTERNS += rgbmatrix/%
+endif
+ifeq ($(CIRCUITPY_PULSEIO),1)
+SRC_PATTERNS += pulseio/%
+endif
+ifeq ($(CIRCUITPY_PS2IO),1)
+SRC_PATTERNS += ps2io/%
+endif
+ifeq ($(CIRCUITPY_RANDOM),1)
+SRC_PATTERNS += random/%
+endif
+ifeq ($(CIRCUITPY_ROTARYIO),1)
+SRC_PATTERNS += rotaryio/%
+endif
+ifeq ($(CIRCUITPY_RTC),1)
+SRC_PATTERNS += rtc/%
+endif
+ifeq ($(CIRCUITPY_SAMD),1)
+SRC_PATTERNS += samd/%
+endif
+ifeq ($(CIRCUITPY_STAGE),1)
+SRC_PATTERNS += _stage/%
+endif
+ifeq ($(CIRCUITPY_STORAGE),1)
+SRC_PATTERNS += storage/%
+endif
+ifeq ($(CIRCUITPY_STRUCT),1)
+SRC_PATTERNS += struct/%
+endif
+ifeq ($(CIRCUITPY_SUPERVISOR),1)
+SRC_PATTERNS += supervisor/%
+endif
+ifeq ($(CIRCUITPY_TIME),1)
+SRC_PATTERNS += time/%
+endif
+ifeq ($(CIRCUITPY_TOUCHIO),1)
+SRC_PATTERNS += touchio/%
+endif
+ifeq ($(CIRCUITPY_UHEAP),1)
+SRC_PATTERNS += uheap/%
+endif
+ifeq ($(CIRCUITPY_USB_HID),1)
+SRC_PATTERNS += usb_hid/%
+endif
+ifeq ($(CIRCUITPY_USB_MIDI),1)
+SRC_PATTERNS += usb_midi/%
+endif
+ifeq ($(CIRCUITPY_USTACK),1)
+SRC_PATTERNS += ustack/%
+endif
+ifeq ($(CIRCUITPY_WATCHDOG),1)
+SRC_PATTERNS += watchdog/%
+endif
+ifeq ($(CIRCUITPY_PEW),1)
+SRC_PATTERNS += _pew/%
+endif
+
+# All possible sources are listed here, and are filtered by SRC_PATTERNS in SRC_COMMON_HAL
+SRC_COMMON_HAL_ALL = \
+ _bleio/__init__.c \
+ _bleio/Adapter.c \
+ _bleio/Attribute.c \
+ _bleio/Characteristic.c \
+ _bleio/CharacteristicBuffer.c \
+ _bleio/Connection.c \
+ _bleio/Descriptor.c \
+ _bleio/PacketBuffer.c \
+ _bleio/Service.c \
+ _bleio/UUID.c \
+ analogio/AnalogIn.c \
+ analogio/AnalogOut.c \
+ analogio/__init__.c \
+ audiobusio/__init__.c \
+ audiobusio/I2SOut.c \
+ audiobusio/PDMIn.c \
+ audiopwmio/__init__.c \
+ audiopwmio/PWMAudioOut.c \
+ audioio/__init__.c \
+ audioio/AudioOut.c \
+ board/__init__.c \
+ busio/I2C.c \
+ busio/SPI.c \
+ busio/UART.c \
+ busio/__init__.c \
+ countio/Counter.c \
+ countio/__init__.c \
+ digitalio/DigitalInOut.c \
+ digitalio/__init__.c \
+ displayio/ParallelBus.c \
+ frequencyio/__init__.c \
+ frequencyio/FrequencyIn.c \
+ i2cslave/I2CSlave.c \
+ i2cslave/__init__.c \
+ microcontroller/Pin.c \
+ microcontroller/Processor.c \
+ microcontroller/__init__.c \
+ neopixel_write/__init__.c \
+ nvm/ByteArray.c \
+ nvm/__init__.c \
+ os/__init__.c \
+ rgbmatrix/RGBMatrix.c \
+ rgbmatrix/__init__.c \
+ pulseio/PWMOut.c \
+ pulseio/PulseIn.c \
+ pulseio/PulseOut.c \
+ pulseio/__init__.c \
+ ps2io/Ps2.c \
+ ps2io/__init__.c \
+ rotaryio/IncrementalEncoder.c \
+ rotaryio/__init__.c \
+ rtc/RTC.c \
+ rtc/__init__.c \
+ supervisor/Runtime.c \
+ supervisor/__init__.c \
+ watchdog/__init__.c \
+ watchdog/WatchDogMode.c \
+ watchdog/WatchDogTimer.c \
+
+SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL))
+
+# These don't have corresponding files in each port but are still located in
+# shared-bindings to make it clear what the contents of the modules are.
+# All possible sources are listed here, and are filtered by SRC_PATTERNS.
+SRC_BINDINGS_ENUMS = \
+$(filter $(SRC_PATTERNS), \
+ _bleio/Address.c \
+ _bleio/Attribute.c \
+ _bleio/ScanEntry.c \
+ digitalio/Direction.c \
+ digitalio/DriveMode.c \
+ digitalio/Pull.c \
+ fontio/Glyph.c \
+ microcontroller/RunMode.c \
+ math/__init__.c \
+ _eve/__init__.c \
+)
+
+SRC_BINDINGS_ENUMS += \
+ util.c
+
+SRC_SHARED_MODULE_ALL = \
+ _bleio/Address.c \
+ _bleio/Attribute.c \
+ _bleio/ScanEntry.c \
+ _bleio/ScanResults.c \
+ _pixelbuf/PixelBuf.c \
+ _pixelbuf/__init__.c \
+ _stage/Layer.c \
+ _stage/Text.c \
+ _stage/__init__.c \
+ audiopwmio/__init__.c \
+ audioio/__init__.c \
+ audiocore/__init__.c \
+ audiocore/RawSample.c \
+ audiocore/WaveFile.c \
+ audiomixer/__init__.c \
+ audiomixer/Mixer.c \
+ audiomixer/MixerVoice.c \
+ audiomp3/__init__.c \
+ audiomp3/MP3Decoder.c \
+ bitbangio/I2C.c \
+ bitbangio/OneWire.c \
+ bitbangio/SPI.c \
+ bitbangio/__init__.c \
+ board/__init__.c \
+ busio/OneWire.c \
+ aesio/__init__.c \
+ aesio/aes.c \
+ displayio/Bitmap.c \
+ displayio/ColorConverter.c \
+ displayio/Display.c \
+ displayio/EPaperDisplay.c \
+ displayio/FourWire.c \
+ displayio/Group.c \
+ displayio/I2CDisplay.c \
+ displayio/OnDiskBitmap.c \
+ displayio/Palette.c \
+ displayio/Shape.c \
+ displayio/TileGrid.c \
+ displayio/__init__.c \
+ vectorio/Circle.c \
+ vectorio/Rectangle.c \
+ vectorio/Polygon.c \
+ vectorio/VectorShape.c \
+ vectorio/__init__.c \
+ fontio/BuiltinFont.c \
+ fontio/__init__.c \
+ framebufferio/FramebufferDisplay.c \
+ framebufferio/__init__.c \
+ gamepad/GamePad.c \
+ gamepad/__init__.c \
+ gamepadshift/GamePadShift.c \
+ gamepadshift/__init__.c \
+ os/__init__.c \
+ random/__init__.c \
+ socket/__init__.c \
+ network/__init__.c \
+ rgbmatrix/RGBMatrix.c \
+ rgbmatrix/__init__.c \
+ storage/__init__.c \
+ struct/__init__.c \
+ time/__init__.c \
+ terminalio/Terminal.c \
+ terminalio/__init__.c \
+ uheap/__init__.c \
+ ustack/__init__.c \
+ _pew/__init__.c \
+ _pew/PewPew.c \
+ _eve/__init__.c
+
+# All possible sources are listed here, and are filtered by SRC_PATTERNS.
+SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL))
+
+# Use the native touchio if requested. This flag is set conditionally in, say, mpconfigport.h.
+# The presence of common-hal/touchio/* # does not imply it's available for all chips in a port,
+# so there is an explicit flag. For example, SAMD21 touchio is native, but SAMD51 is not.
+ifeq ($(CIRCUITPY_TOUCHIO_USE_NATIVE),1)
+SRC_COMMON_HAL_ALL += \
+ touchio/TouchIn.c \
+ touchio/__init__.c
+else
+SRC_SHARED_MODULE_ALL += \
+ touchio/TouchIn.c \
+ touchio/__init__.c
+endif
+ifeq ($(CIRCUITPY_AUDIOMP3),1)
+SRC_MOD += $(addprefix lib/mp3/src/, \
+ bitstream.c \
+ buffers.c \
+ dct32.c \
+ dequant.c \
+ dqchan.c \
+ huffman.c \
+ hufftabs.c \
+ imdct.c \
+ mp3dec.c \
+ mp3tabs.c \
+ polyphase.c \
+ scalfact.c \
+ stproc.c \
+ subband.c \
+ trigtabs.c \
+)
+$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x,0)' -D'MPDEC_FREE(x)=m_free(x)'
+endif
+ifeq ($(CIRCUITPY_RGBMATRIX),1)
+SRC_MOD += $(addprefix lib/protomatter/, \
+ core.c \
+)
+$(BUILD)/lib/protomatter/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces
+endif
+
+# All possible sources are listed here, and are filtered by SRC_PATTERNS.
+SRC_SHARED_MODULE_INTERNAL = \
+$(filter $(SRC_PATTERNS), \
+ displayio/display_core.c \
+)
+
+ifeq ($(INTERNAL_LIBM),1)
+SRC_LIBM = \
+$(addprefix lib/,\
+ libm/math.c \
+ libm/roundf.c \
+ libm/fmodf.c \
+ libm/nearbyintf.c \
+ libm/ef_sqrt.c \
+ libm/kf_rem_pio2.c \
+ libm/kf_sin.c \
+ libm/kf_cos.c \
+ libm/kf_tan.c \
+ libm/ef_rem_pio2.c \
+ libm/sf_sin.c \
+ libm/sf_cos.c \
+ libm/sf_tan.c \
+ libm/sf_frexp.c \
+ libm/sf_modf.c \
+ libm/sf_ldexp.c \
+ libm/asinfacosf.c \
+ libm/atanf.c \
+ libm/atan2f.c \
+ )
+ifeq ($(CIRCUITPY_ULAB),1)
+SRC_LIBM += \
+$(addprefix lib/,\
+ libm/acoshf.c \
+ libm/asinhf.c \
+ libm/atanhf.c \
+ libm/erf_lgamma.c \
+ libm/log1pf.c \
+ libm/sf_erf.c \
+ libm/wf_lgamma.c \
+ libm/wf_tgamma.c \
+ )
+endif
+endif
+
+ifdef LD_TEMPLATE_FILE
+# Generate a linker script (.ld file) from a template, for those builds that use it.
+GENERATED_LD_FILE = $(BUILD)/$(notdir $(patsubst %.template.ld,%.ld,$(LD_TEMPLATE_FILE)))
+#
+# ld_defines.pp is generated from ld_defines.c. See py/mkrules.mk.
+# Run gen_ld_files.py over ALL *.template.ld files, not just LD_TEMPLATE_FILE,
+# because it may include other template files.
+$(GENERATED_LD_FILE): $(BUILD)/ld_defines.pp boards/*.template.ld
+ $(STEPECHO) "GEN $@"
+ $(Q)$(PYTHON3) $(TOP)/tools/gen_ld_files.py --defines $< --out_dir $(BUILD) boards/*.template.ld
+endif
+
+.PHONY: check-release-needs-clean-build
+
+check-release-needs-clean-build:
+ @echo "RELEASE_NEEDS_CLEAN_BUILD = $(RELEASE_NEEDS_CLEAN_BUILD)"
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
new file mode 100644
index 000000000..3fbb46900
--- /dev/null
+++ b/py/circuitpy_mpconfig.h
@@ -0,0 +1,768 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file contains settings that are common across CircuitPython ports, to make
+// sure that the same feature set and settings are used, such as in atmel-samd
+// and nrf.
+
+#ifndef __INCLUDED_MPCONFIG_CIRCUITPY_H
+#define __INCLUDED_MPCONFIG_CIRCUITPY_H
+
+#include <stdint.h>
+#include <stdatomic.h>
+
+// This is CircuitPython.
+#define CIRCUITPY 1
+
+// REPR_C encodes qstrs, 31-bit ints, and 30-bit floats in a single 32-bit word.
+#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
+
+// options to control how MicroPython is built
+// TODO(tannewt): Reduce this number if we want the REPL to function under 512
+// free bytes.
+// #define MICROPY_ALLOC_PARSE_RULE_INIT (64)
+
+// Sorted alphabetically for easy finding.
+//
+// default is 128; consider raising to reduce fragmentation.
+#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
+// default is 512.
+#define MICROPY_ALLOC_PATH_MAX (256)
+#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_COMP_CONST (1)
+#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
+#define MICROPY_COMP_MODULE_CONST (1)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
+#define MICROPY_DEBUG_PRINTERS (0)
+#define MICROPY_EMIT_INLINE_THUMB (CIRCUITPY_ENABLE_MPY_NATIVE)
+#define MICROPY_EMIT_THUMB (CIRCUITPY_ENABLE_MPY_NATIVE)
+#define MICROPY_EMIT_X64 (0)
+#define MICROPY_ENABLE_DOC_STRING (0)
+#define MICROPY_ENABLE_FINALISER (1)
+#define MICROPY_ENABLE_GC (1)
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
+#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0)
+#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
+#define MICROPY_GC_ALLOC_THRESHOLD (0)
+#define MICROPY_HELPER_LEXER_UNIX (0)
+#define MICROPY_HELPER_REPL (1)
+#define MICROPY_KBD_EXCEPTION (1)
+#define MICROPY_MEM_STATS (0)
+#define MICROPY_MODULE_BUILTIN_INIT (1)
+#define MICROPY_NONSTANDARD_TYPECODES (0)
+#define MICROPY_OPT_COMPUTED_GOTO (1)
+#define MICROPY_PERSISTENT_CODE_LOAD (1)
+
+#define MICROPY_PY_ARRAY (1)
+#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
+#define MICROPY_PY_ASYNC_AWAIT (0)
+#define MICROPY_PY_ATTRTUPLE (1)
+
+#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
+#define MICROPY_PY_BUILTINS_ENUMERATE (1)
+#define MICROPY_PY_BUILTINS_FILTER (1)
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
+#define MICROPY_PY_BUILTINS_INPUT (1)
+#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
+#define MICROPY_PY_BUILTINS_MIN_MAX (1)
+#define MICROPY_PY_BUILTINS_PROPERTY (1)
+#define MICROPY_PY_BUILTINS_REVERSED (1)
+#define MICROPY_PY_BUILTINS_ROUND_INT (1)
+#define MICROPY_PY_BUILTINS_SET (1)
+#define MICROPY_PY_BUILTINS_SLICE (1)
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
+
+#define MICROPY_PY_CMATH (0)
+#define MICROPY_PY_COLLECTIONS (1)
+#define MICROPY_PY_DESCRIPTORS (1)
+#define MICROPY_PY_IO_FILEIO (1)
+#define MICROPY_PY_GC (1)
+// Supplanted by shared-bindings/math
+#define MICROPY_PY_MATH (0)
+#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
+// Supplanted by shared-bindings/struct
+#define MICROPY_PY_STRUCT (0)
+#define MICROPY_PY_SYS (1)
+#define MICROPY_PY_SYS_MAXSIZE (1)
+#define MICROPY_PY_SYS_STDFILES (1)
+// Supplanted by shared-bindings/random
+#define MICROPY_PY_URANDOM (0)
+#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
+#define MICROPY_PY___FILE__ (1)
+
+#define MICROPY_QSTR_BYTES_IN_HASH (1)
+#define MICROPY_REPL_AUTO_INDENT (1)
+#define MICROPY_REPL_EVENT_DRIVEN (0)
+#define MICROPY_STACK_CHECK (1)
+#define MICROPY_STREAMS_NON_BLOCK (1)
+#ifndef MICROPY_USE_INTERNAL_PRINTF
+#define MICROPY_USE_INTERNAL_PRINTF (1)
+#endif
+
+// fatfs configuration used in ffconf.h
+//
+// 1 = SFN/ANSI 437=LFN/U.S.(OEM)
+#define MICROPY_FATFS_ENABLE_LFN (1)
+#define MICROPY_FATFS_LFN_CODE_PAGE (437)
+#define MICROPY_FATFS_USE_LABEL (1)
+#define MICROPY_FATFS_RPATH (2)
+#define MICROPY_FATFS_MULTI_PARTITION (1)
+
+// Only enable this if you really need it. It allocates a byte cache of this size.
+// #define MICROPY_FATFS_MAX_SS (4096)
+
+#define FILESYSTEM_BLOCK_SIZE (512)
+
+#define MICROPY_VFS (1)
+#define MICROPY_VFS_FAT (MICROPY_VFS)
+#define MICROPY_READER_VFS (MICROPY_VFS)
+
+// type definitions for the specific machine
+
+#define BYTES_PER_WORD (4)
+
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
+
+// Track stack usage. Expose results via ustack module.
+#define MICROPY_MAX_STACK_USAGE (0)
+
+// This port is intended to be 32-bit, but unfortunately, int32_t for
+// different targets may be defined in different ways - either as int
+// or as long. This requires different printf formatting specifiers
+// to print such value. So, we avoid int32_t and use int directly.
+#define UINT_FMT "%u"
+#define INT_FMT "%d"
+typedef int mp_int_t; // must be pointer size
+typedef unsigned mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+
+#define mp_type_fileio mp_type_vfs_fat_fileio
+#define mp_type_textio mp_type_vfs_fat_textio
+
+#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open_obj mp_vfs_open_obj
+
+
+// extra built in names to add to the global namespace
+#define MICROPY_PORT_BUILTINS \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// board-specific definitions, which control and may override definitions below.
+#include "mpconfigboard.h"
+
+// Turning off FULL_BUILD removes some functionality to reduce flash size on tiny SAMD21s
+#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (CIRCUITPY_FULL_BUILD)
+#define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
+#define MICROPY_COMP_FSTRING_LITERAL (MICROPY_CPYTHON_COMPAT)
+#define MICROPY_MODULE_WEAK_LINKS (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_ALL_SPECIAL_METHODS (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_BUILTINS_COMPLEX (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_BUILTINS_FROZENSET (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_BUILTINS_STR_CENTER (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_BUILTINS_STR_PARTITION (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_BUILTINS_STR_SPLITLINES (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_UERRNO (CIRCUITPY_FULL_BUILD)
+// Opposite setting is deliberate.
+#define MICROPY_PY_UERRNO_ERRORCODE (!CIRCUITPY_FULL_BUILD)
+#ifndef MICROPY_PY_URE
+#define MICROPY_PY_URE (CIRCUITPY_FULL_BUILD)
+#endif
+#define MICROPY_PY_URE_MATCH_GROUPS (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_URE_MATCH_SPAN_START_END (CIRCUITPY_FULL_BUILD)
+#define MICROPY_PY_URE_SUB (CIRCUITPY_FULL_BUILD)
+
+// LONGINT_IMPL_xxx are defined in the Makefile.
+//
+#ifdef LONGINT_IMPL_NONE
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
+#endif
+
+#ifdef LONGINT_IMPL_MPZ
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
+#define MP_SSIZE_MAX (0x7fffffff)
+#endif
+
+#ifdef LONGINT_IMPL_LONGLONG
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)
+#define MP_SSIZE_MAX (0x7fffffff)
+#endif
+
+#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
+#define MICROPY_PY_REVERSE_SPECIAL_METHODS (CIRCUITPY_FULL_BUILD)
+#endif
+
+#if INTERNAL_FLASH_FILESYSTEM == 0 && QSPI_FLASH_FILESYSTEM == 0 && SPI_FLASH_FILESYSTEM == 0 && !DISABLE_FILESYSTEM
+#error No *_FLASH_FILESYSTEM set!
+#endif
+
+// These CIRCUITPY_xxx values should all be defined in the *.mk files as being on or off.
+// So if any are not defined in *.mk, they'll throw an error here.
+
+#if CIRCUITPY_AESIO
+extern const struct _mp_obj_module_t aesio_module;
+#define AESIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_aesio), (mp_obj_t)&aesio_module },
+#else
+#define AESIO_MODULE
+#endif
+
+#if CIRCUITPY_ANALOGIO
+#define ANALOGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module },
+extern const struct _mp_obj_module_t analogio_module;
+#else
+#define ANALOGIO_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOBUSIO
+#define AUDIOBUSIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiobusio), (mp_obj_t)&audiobusio_module },
+extern const struct _mp_obj_module_t audiobusio_module;
+#else
+#define AUDIOBUSIO_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOCORE
+#define AUDIOCORE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiocore), (mp_obj_t)&audiocore_module },
+extern const struct _mp_obj_module_t audiocore_module;
+#else
+#define AUDIOCORE_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOIO
+#define AUDIOIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module },
+extern const struct _mp_obj_module_t audioio_module;
+#else
+#define AUDIOIO_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOMIXER
+#define AUDIOMIXER_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiomixer), (mp_obj_t)&audiomixer_module },
+extern const struct _mp_obj_module_t audiomixer_module;
+#else
+#define AUDIOMIXER_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOMP3
+#define AUDIOMP3_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiomp3), (mp_obj_t)&audiomp3_module },
+extern const struct _mp_obj_module_t audiomp3_module;
+#else
+#define AUDIOMP3_MODULE
+#endif
+
+#if CIRCUITPY_AUDIOPWMIO
+#define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module },
+extern const struct _mp_obj_module_t audiopwmio_module;
+#else
+#define AUDIOPWMIO_MODULE
+#endif
+
+#if CIRCUITPY_BITBANGIO
+#define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module },
+extern const struct _mp_obj_module_t bitbangio_module;
+#else
+#define BITBANGIO_MODULE
+#endif
+
+#if CIRCUITPY_BLEIO
+#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__bleio), (mp_obj_t)&bleio_module },
+extern const struct _mp_obj_module_t bleio_module;
+#else
+#define BLEIO_MODULE
+#endif
+
+#if CIRCUITPY_BOARD
+#define BOARD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module },
+extern const struct _mp_obj_module_t board_module;
+
+#define BOARD_I2C (defined(DEFAULT_I2C_BUS_SDA) && defined(DEFAULT_I2C_BUS_SCL))
+#define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI))
+#define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX))
+
+// I2C and SPI are always allocated off the heap.
+
+#if BOARD_UART
+#define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus;
+#else
+#define BOARD_UART_ROOT_POINTER
+#endif
+
+#else
+#define BOARD_MODULE
+#define BOARD_UART_ROOT_POINTER
+#endif
+
+#if CIRCUITPY_BUSIO
+extern const struct _mp_obj_module_t busio_module;
+#define BUSIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module },
+#else
+#define BUSIO_MODULE
+#endif
+
+#if CIRCUITPY_COUNTIO
+extern const struct _mp_obj_module_t countio_module;
+#define COUNTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_countio), (mp_obj_t)&countio_module },
+#else
+#define COUNTIO_MODULE
+#endif
+
+#if CIRCUITPY_DIGITALIO
+extern const struct _mp_obj_module_t digitalio_module;
+#define DIGITALIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_digitalio), (mp_obj_t)&digitalio_module },
+#else
+#define DIGITALIO_MODULE
+#endif
+
+#if CIRCUITPY_DISPLAYIO
+extern const struct _mp_obj_module_t displayio_module;
+extern const struct _mp_obj_module_t fontio_module;
+extern const struct _mp_obj_module_t terminalio_module;
+#define DISPLAYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_displayio), (mp_obj_t)&displayio_module },
+#define FONTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_fontio), (mp_obj_t)&fontio_module },
+#define TERMINALIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_terminalio), (mp_obj_t)&terminalio_module },
+#ifndef CIRCUITPY_DISPLAY_LIMIT
+#define CIRCUITPY_DISPLAY_LIMIT (1)
+#endif
+#else
+#define DISPLAYIO_MODULE
+#define FONTIO_MODULE
+#define TERMINALIO_MODULE
+#define CIRCUITPY_DISPLAY_LIMIT (0)
+#endif
+
+#if CIRCUITPY_FRAMEBUFFERIO
+extern const struct _mp_obj_module_t framebufferio_module;
+#define FRAMEBUFFERIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_framebufferio), (mp_obj_t)&framebufferio_module },
+#else
+#define FRAMEBUFFERIO_MODULE
+#endif
+
+#if CIRCUITPY_VECTORIO
+extern const struct _mp_obj_module_t vectorio_module;
+#define VECTORIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_vectorio), (mp_obj_t)&vectorio_module },
+#else
+#define VECTORIO_MODULE
+#endif
+
+#if CIRCUITPY_FREQUENCYIO
+extern const struct _mp_obj_module_t frequencyio_module;
+#define FREQUENCYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_frequencyio), (mp_obj_t)&frequencyio_module },
+#else
+#define FREQUENCYIO_MODULE
+#endif
+
+#if CIRCUITPY_GAMEPAD
+extern const struct _mp_obj_module_t gamepad_module;
+#define GAMEPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
+#else
+#define GAMEPAD_MODULE
+#endif
+
+#if CIRCUITPY_GAMEPADSHIFT
+extern const struct _mp_obj_module_t gamepadshift_module;
+#define GAMEPADSHIFT_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_gamepadshift),(mp_obj_t)&gamepadshift_module },
+#else
+#define GAMEPADSHIFT_MODULE
+#endif
+
+#if CIRCUITPY_GAMEPAD || CIRCUITPY_GAMEPADSHIFT
+// Scan gamepad every 32ms
+#define CIRCUITPY_GAMEPAD_TICKS 0x1f
+#define GAMEPAD_ROOT_POINTERS mp_obj_t gamepad_singleton;
+#else
+#define GAMEPAD_ROOT_POINTERS
+#endif
+
+#if CIRCUITPY_I2CSLAVE
+extern const struct _mp_obj_module_t i2cslave_module;
+#define I2CSLAVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_i2cslave), (mp_obj_t)&i2cslave_module },
+#else
+#define I2CSLAVE_MODULE
+#endif
+
+#if CIRCUITPY_MATH
+extern const struct _mp_obj_module_t math_module;
+#define MATH_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module },
+#else
+#define MATH_MODULE
+#endif
+
+#if CIRCUITPY__EVE
+extern const struct _mp_obj_module_t _eve_module;
+#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module },
+#else
+#define _EVE_MODULE
+#endif
+
+#if CIRCUITPY_MICROCONTROLLER
+extern const struct _mp_obj_module_t microcontroller_module;
+#define MICROCONTROLLER_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)&microcontroller_module },
+#else
+#define MICROCONTROLLER_MODULE
+#endif
+
+#if CIRCUITPY_NEOPIXEL_WRITE
+extern const struct _mp_obj_module_t neopixel_write_module;
+#define NEOPIXEL_WRITE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module },
+#else
+#define NEOPIXEL_WRITE_MODULE
+#endif
+
+#if CIRCUITPY_NETWORK
+extern const struct _mp_obj_module_t network_module;
+extern const struct _mp_obj_module_t socket_module;
+#define NETWORK_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&network_module },
+#define SOCKET_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&socket_module },
+#define NETWORK_ROOT_POINTERS mp_obj_list_t mod_network_nic_list;
+#if MICROPY_PY_WIZNET5K
+ extern const struct _mp_obj_module_t wiznet_module;
+ #define WIZNET_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_wiznet), (mp_obj_t)&wiznet_module },
+#endif
+#else
+#define NETWORK_MODULE
+#define SOCKET_MODULE
+#define WIZNET_MODULE
+#define NETWORK_ROOT_POINTERS
+#endif
+
+// This is not a top-level module; it's microcontroller.nvm.
+#if CIRCUITPY_NVM
+extern const struct _mp_obj_module_t nvm_module;
+#endif
+
+#if CIRCUITPY_OS
+extern const struct _mp_obj_module_t os_module;
+#define OS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module },
+#define OS_MODULE_ALT_NAME { MP_OBJ_NEW_QSTR(MP_QSTR__os), (mp_obj_t)&os_module },
+#else
+#define OS_MODULE
+#define OS_MODULE_ALT_NAME
+#endif
+
+#if CIRCUITPY_PEW
+extern const struct _mp_obj_module_t pew_module;
+#define PEW_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pew),(mp_obj_t)&pew_module },
+#else
+#define PEW_MODULE
+#endif
+
+#if CIRCUITPY_PIXELBUF
+extern const struct _mp_obj_module_t pixelbuf_module;
+#define PIXELBUF_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pixelbuf),(mp_obj_t)&pixelbuf_module },
+#else
+#define PIXELBUF_MODULE
+#endif
+
+#if CIRCUITPY_RGBMATRIX
+extern const struct _mp_obj_module_t rgbmatrix_module;
+#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module },
+#else
+#define RGBMATRIX_MODULE
+#endif
+
+#if CIRCUITPY_PULSEIO
+extern const struct _mp_obj_module_t pulseio_module;
+#define PULSEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module },
+#else
+#define PULSEIO_MODULE
+#endif
+
+#if CIRCUITPY_PS2IO
+extern const struct _mp_obj_module_t ps2io_module;
+#define PS2IO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ps2io), (mp_obj_t)&ps2io_module },
+#else
+#define PS2IO_MODULE
+#endif
+
+#if CIRCUITPY_RANDOM
+extern const struct _mp_obj_module_t random_module;
+#define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module },
+#else
+#define RANDOM_MODULE
+#endif
+
+#if CIRCUITPY_ROTARYIO
+extern const struct _mp_obj_module_t rotaryio_module;
+#define ROTARYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rotaryio), (mp_obj_t)&rotaryio_module },
+#else
+#define ROTARYIO_MODULE
+#endif
+
+#if CIRCUITPY_RTC
+extern const struct _mp_obj_module_t rtc_module;
+#define RTC_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rtc), (mp_obj_t)&rtc_module },
+#else
+#define RTC_MODULE
+#endif
+
+#if CIRCUITPY_SAMD
+extern const struct _mp_obj_module_t samd_module;
+#define SAMD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_samd),(mp_obj_t)&samd_module },
+#else
+#define SAMD_MODULE
+#endif
+
+#if CIRCUITPY_STAGE
+extern const struct _mp_obj_module_t stage_module;
+#define STAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module },
+#else
+#define STAGE_MODULE
+#endif
+
+#if CIRCUITPY_STORAGE
+extern const struct _mp_obj_module_t storage_module;
+#define STORAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module },
+#else
+#define STORAGE_MODULE
+#endif
+
+#if CIRCUITPY_STRUCT
+extern const struct _mp_obj_module_t struct_module;
+#define STRUCT_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module },
+#else
+#define STRUCT_MODULE
+#endif
+
+#if CIRCUITPY_SUPERVISOR
+extern const struct _mp_obj_module_t supervisor_module;
+#define SUPERVISOR_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_supervisor), (mp_obj_t)&supervisor_module },
+#else
+#define SUPERVISOR_MODULE
+#endif
+
+#if CIRCUITPY_TIME
+extern const struct _mp_obj_module_t time_module;
+#define TIME_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module },
+#define TIME_MODULE_ALT_NAME { MP_OBJ_NEW_QSTR(MP_QSTR__time), (mp_obj_t)&time_module },
+#else
+#define TIME_MODULE
+#define TIME_MODULE_ALT_NAME
+#endif
+
+#if CIRCUITPY_TOUCHIO
+extern const struct _mp_obj_module_t touchio_module;
+#define TOUCHIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_touchio), (mp_obj_t)&touchio_module },
+#else
+#define TOUCHIO_MODULE
+#endif
+
+#if CIRCUITPY_UHEAP
+extern const struct _mp_obj_module_t uheap_module;
+#define UHEAP_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module },
+#else
+#define UHEAP_MODULE
+#endif
+
+#if CIRCUITPY_USB_HID
+extern const struct _mp_obj_module_t usb_hid_module;
+#define USB_HID_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
+#else
+#define USB_HID_MODULE
+#endif
+
+#if CIRCUITPY_USB_MIDI
+extern const struct _mp_obj_module_t usb_midi_module;
+#define USB_MIDI_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_usb_midi),(mp_obj_t)&usb_midi_module },
+#else
+#define USB_MIDI_MODULE
+#endif
+
+#if CIRCUITPY_USTACK
+extern const struct _mp_obj_module_t ustack_module;
+#define USTACK_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ustack),(mp_obj_t)&ustack_module },
+#else
+#define USTACK_MODULE
+#endif
+
+// These modules are not yet in shared-bindings, but we prefer the non-uxxx names.
+#if MICROPY_PY_UERRNO
+#define ERRNO_MODULE { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) },
+#else
+#define ERRNO_MODULE
+#endif
+
+#if MICROPY_PY_UJSON
+#define JSON_MODULE { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) },
+#else
+#define JSON_MODULE
+#endif
+
+#if defined(CIRCUITPY_ULAB) && CIRCUITPY_ULAB
+// ulab requires reverse special methods
+#if defined(MICROPY_PY_REVERSE_SPECIAL_METHODS) && !MICROPY_PY_REVERSE_SPECIAL_METHODS
+#error "ulab requires MICROPY_PY_REVERSE_SPECIAL_METHODS"
+#endif
+#define ULAB_MODULE \
+ { MP_ROM_QSTR(MP_QSTR_ulab), MP_ROM_PTR(&ulab_user_cmodule) },
+#else
+#define ULAB_MODULE
+#endif
+
+#if MICROPY_PY_URE
+#define RE_MODULE { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) },
+#else
+#define RE_MODULE
+#endif
+
+// This is not a top-level module; it's microcontroller.watchdog.
+#if CIRCUITPY_WATCHDOG
+extern const struct _mp_obj_module_t watchdog_module;
+#define WATCHDOG_MODULE { MP_ROM_QSTR(MP_QSTR_watchdog), MP_ROM_PTR(&watchdog_module) },
+#else
+#define WATCHDOG_MODULE
+#endif
+
+// Define certain native modules with weak links so they can be replaced with Python
+// implementations. This list may grow over time.
+#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
+ OS_MODULE \
+ TIME_MODULE \
+
+// Native modules that are weak links can be accessed directly
+// by prepending their name with an underscore. This list should correspond to
+// MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS, assuming you want the native modules
+// to be accessible when overriden.
+#define MICROPY_PORT_BUILTIN_MODULE_ALT_NAMES \
+ OS_MODULE_ALT_NAME \
+ TIME_MODULE_ALT_NAME \
+
+// This is an inclusive list that should correspond to the CIRCUITPY_XXX list above,
+// including dependencies such as TERMINALIO depending on DISPLAYIO (shown by indentation).
+// Some of these definitions will be blank depending on what is turned on and off.
+// Some are omitted because they're in MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS above.
+#define MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS \
+ AESIO_MODULE \
+ ANALOGIO_MODULE \
+ AUDIOBUSIO_MODULE \
+ AUDIOCORE_MODULE \
+ AUDIOIO_MODULE \
+ AUDIOMIXER_MODULE \
+ AUDIOMP3_MODULE \
+ AUDIOPWMIO_MODULE \
+ BITBANGIO_MODULE \
+ BLEIO_MODULE \
+ BOARD_MODULE \
+ BUSIO_MODULE \
+ COUNTIO_MODULE \
+ DIGITALIO_MODULE \
+ DISPLAYIO_MODULE \
+ FONTIO_MODULE \
+ TERMINALIO_MODULE \
+ VECTORIO_MODULE \
+ ERRNO_MODULE \
+ FRAMEBUFFERIO_MODULE \
+ FREQUENCYIO_MODULE \
+ GAMEPAD_MODULE \
+ GAMEPADSHIFT_MODULE \
+ I2CSLAVE_MODULE \
+ JSON_MODULE \
+ MATH_MODULE \
+ _EVE_MODULE \
+ MICROCONTROLLER_MODULE \
+ NEOPIXEL_WRITE_MODULE \
+ NETWORK_MODULE \
+ SOCKET_MODULE \
+ WIZNET_MODULE \
+ PEW_MODULE \
+ PIXELBUF_MODULE \
+ PS2IO_MODULE \
+ PULSEIO_MODULE \
+ RANDOM_MODULE \
+ RE_MODULE \
+ RGBMATRIX_MODULE \
+ ROTARYIO_MODULE \
+ RTC_MODULE \
+ SAMD_MODULE \
+ STAGE_MODULE \
+ STORAGE_MODULE \
+ STRUCT_MODULE \
+ SUPERVISOR_MODULE \
+ TOUCHIO_MODULE \
+ UHEAP_MODULE \
+ USB_HID_MODULE \
+ USB_MIDI_MODULE \
+ USTACK_MODULE \
+ WATCHDOG_MODULE \
+
+// If weak links are enabled, just include strong links in the main list of modules,
+// and also include the underscore alternate names.
+#if MICROPY_MODULE_WEAK_LINKS
+#define MICROPY_PORT_BUILTIN_MODULES \
+ MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS \
+ MICROPY_PORT_BUILTIN_MODULE_ALT_NAMES
+#else
+// If weak links are disabled, included both strong and potentially weak lines
+#define MICROPY_PORT_BUILTIN_MODULES \
+ MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS \
+ MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
+#endif
+
+// We need to provide a declaration/definition of alloca()
+#include <alloca.h>
+
+#define MP_STATE_PORT MP_STATE_VM
+
+#include "supervisor/flash_root_pointers.h"
+
+#define CIRCUITPY_COMMON_ROOT_POINTERS \
+ const char *readline_hist[8]; \
+ vstr_t *repl_line; \
+ mp_obj_t rtc_time_source; \
+ GAMEPAD_ROOT_POINTERS \
+ mp_obj_t pew_singleton; \
+ mp_obj_t terminal_tilegrid_tiles; \
+ BOARD_UART_ROOT_POINTER \
+ FLASH_ROOT_POINTERS \
+ NETWORK_ROOT_POINTERS \
+
+void supervisor_run_background_tasks_if_tick(void);
+#define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick())
+
+// TODO: Used in wiznet5k driver, but may not be needed in the long run.
+#define MICROPY_THREAD_YIELD()
+
+#define MICROPY_VM_HOOK_LOOP RUN_BACKGROUND_TASKS;
+#define MICROPY_VM_HOOK_RETURN RUN_BACKGROUND_TASKS;
+
+// CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload.
+#ifndef CIRCUITPY_AUTORELOAD_DELAY_MS
+#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+#endif
+
+#ifndef CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS
+#define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000
+#endif
+
+#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt"
+
+#define CIRCUITPY_VERBOSE_BLE 0
+
+#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
new file mode 100644
index 000000000..865654a0d
--- /dev/null
+++ b/py/circuitpy_mpconfig.mk
@@ -0,0 +1,237 @@
+#
+# This file is part of the MicroPython project, http://micropython.org/
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2019 Dan Halbert for Adafruit Industries
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Boards default to all modules enabled (with exceptions)
+# Manually disable by overriding in #mpconfigboard.mk
+
+# Smaller builds can be forced for resource constrained chips (typically SAMD21s
+# without external flash) by setting CIRCUITPY_FULL_BUILD=0. Avoid using this
+# for merely incomplete ports, as it changes settings in other files.
+CIRCUITPY_FULL_BUILD ?= 1
+CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD)
+
+
+CIRCUITPY_AESIO ?= 0
+CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO)
+
+CIRCUITPY_ANALOGIO ?= 1
+CFLAGS += -DCIRCUITPY_ANALOGIO=$(CIRCUITPY_ANALOGIO)
+
+CIRCUITPY_AUDIOBUSIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_AUDIOBUSIO=$(CIRCUITPY_AUDIOBUSIO)
+
+CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO)
+
+CIRCUITPY_AUDIOIO_COMPAT ?= $(CIRCUITPY_AUDIOIO)
+CFLAGS += -DCIRCUITPY_AUDIOIO_COMPAT=$(CIRCUITPY_AUDIOIO_COMPAT)
+
+CIRCUITPY_AUDIOPWMIO ?= 0
+CFLAGS += -DCIRCUITPY_AUDIOPWMIO=$(CIRCUITPY_AUDIOPWMIO)
+
+ifndef CIRCUITPY_AUDIOCORE
+ifeq ($(CIRCUITPY_AUDIOPWMIO),1)
+CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOPWMIO)
+else
+CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO)
+endif
+endif
+CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE)
+
+CIRCUITPY_AUDIOMIXER ?= $(CIRCUITPY_AUDIOIO)
+CFLAGS += -DCIRCUITPY_AUDIOMIXER=$(CIRCUITPY_AUDIOMIXER)
+
+ifndef CIRCUITPY_AUDIOMP3
+ifeq ($(CIRCUITPY_FULL_BUILD),1)
+CIRCUITPY_AUDIOMP3 = $(CIRCUITPY_AUDIOCORE)
+else
+CIRCUITPY_AUDIOMP3 = 0
+endif
+endif
+CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3)
+
+CIRCUITPY_BITBANGIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO)
+
+# Explicitly enabled for boards that support _bleio.
+CIRCUITPY_BLEIO ?= 0
+CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO)
+
+CIRCUITPY_BOARD ?= 1
+CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD)
+
+CIRCUITPY_BUSIO ?= 1
+CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO)
+
+CIRCUITPY_DIGITALIO ?= 1
+CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO)
+
+CIRCUITPY_COUNTIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO)
+
+CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO)
+
+CIRCUITPY_FRAMEBUFFERIO ?= 0
+CFLAGS += -DCIRCUITPY_FRAMEBUFFERIO=$(CIRCUITPY_FRAMEBUFFERIO)
+
+CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO)
+CFLAGS += -DCIRCUITPY_VECTORIO=$(CIRCUITPY_VECTORIO)
+
+CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO)
+
+CIRCUITPY_GAMEPAD ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_GAMEPAD=$(CIRCUITPY_GAMEPAD)
+
+CIRCUITPY_GAMEPADSHIFT ?= 0
+CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
+
+CIRCUITPY_I2CSLAVE ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_I2CSLAVE=$(CIRCUITPY_I2CSLAVE)
+
+CIRCUITPY_MATH ?= 1
+CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH)
+
+CIRCUITPY__EVE ?= 0
+CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
+
+CIRCUITPY_MICROCONTROLLER ?= 1
+CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER)
+
+CIRCUITPY_NEOPIXEL_WRITE ?= 1
+CFLAGS += -DCIRCUITPY_NEOPIXEL_WRITE=$(CIRCUITPY_NEOPIXEL_WRITE)
+
+# Enabled on SAMD51. Won't fit on SAMD21 builds. Not tested on nRF or STM32F4 builds.
+CIRCUITPY_NETWORK ?= 0
+CFLAGS += -DCIRCUITPY_NETWORK=$(CIRCUITPY_NETWORK)
+
+CIRCUITPY_NVM ?= 1
+CFLAGS += -DCIRCUITPY_NVM=$(CIRCUITPY_NVM)
+
+CIRCUITPY_OS ?= 1
+CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS)
+
+CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF)
+
+# Only for SAMD boards for the moment
+CIRCUITPY_RGBMATRIX ?= 0
+CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX)
+
+CIRCUITPY_PULSEIO ?= 1
+CFLAGS += -DCIRCUITPY_PULSEIO=$(CIRCUITPY_PULSEIO)
+
+# Only for SAMD boards for the moment
+CIRCUITPY_PS2IO ?= 0
+CFLAGS += -DCIRCUITPY_PS2IO=$(CIRCUITPY_PS2IO)
+
+CIRCUITPY_RANDOM ?= 1
+CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM)
+
+CIRCUITPY_ROTARYIO ?= 1
+CFLAGS += -DCIRCUITPY_ROTARYIO=$(CIRCUITPY_ROTARYIO)
+
+CIRCUITPY_RTC ?= 1
+CFLAGS += -DCIRCUITPY_RTC=$(CIRCUITPY_RTC)
+
+# CIRCUITPY_SAMD is handled in the atmel-samd tree.
+# Only for SAMD chips.
+# Assume not a SAMD build.
+CIRCUITPY_SAMD ?= 0
+CFLAGS += -DCIRCUITPY_SAMD=$(CIRCUITPY_SAMD)
+
+# Currently always off.
+CIRCUITPY_STAGE ?= 0
+CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE)
+
+CIRCUITPY_STORAGE ?= 1
+CFLAGS += -DCIRCUITPY_STORAGE=$(CIRCUITPY_STORAGE)
+
+CIRCUITPY_STRUCT ?= 1
+CFLAGS += -DCIRCUITPY_STRUCT=$(CIRCUITPY_STRUCT)
+
+CIRCUITPY_SUPERVISOR ?= 1
+CFLAGS += -DCIRCUITPY_SUPERVISOR=$(CIRCUITPY_SUPERVISOR)
+
+CIRCUITPY_TIME ?= 1
+CFLAGS += -DCIRCUITPY_TIME=$(CIRCUITPY_TIME)
+
+# touchio might be native or generic. See circuitpy_defns.mk.
+CIRCUITPY_TOUCHIO_USE_NATIVE ?= 0
+CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
+
+CIRCUITPY_TOUCHIO ?= 1
+CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
+
+# For debugging.
+CIRCUITPY_UHEAP ?= 0
+CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)
+
+CIRCUITPY_USB_HID ?= 1
+CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
+
+CIRCUITPY_USB_MIDI ?= 1
+CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
+
+CIRCUITPY_PEW ?= 0
+CFLAGS += -DCIRCUITPY_PEW=$(CIRCUITPY_PEW)
+
+# For debugging.
+CIRCUITPY_USTACK ?= 0
+CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK)
+
+# Non-module conditionals
+
+CIRCUITPY_BITBANG_APA102 ?= 0
+CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102)
+
+# Should busio.I2C() check for pullups?
+# Some boards in combination with certain peripherals may not want this.
+CIRCUITPY_REQUIRE_I2C_PULLUPS ?= 1
+CFLAGS += -DCIRCUITPY_REQUIRE_I2C_PULLUPS=$(CIRCUITPY_REQUIRE_I2C_PULLUPS)
+
+# REPL over BLE
+CIRCUITPY_SERIAL_BLE ?= 0
+CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE)
+
+CIRCUITPY_BLE_FILE_SERVICE ?= 0
+CFLAGS += -DCIRCUITPY_BLE_FILE_SERVICE=$(CIRCUITPY_BLE_FILE_SERVICE)
+
+# REPL over UART
+CIRCUITPY_SERIAL_UART ?= 0
+CFLAGS += -DCIRCUITPY_SERIAL_UART=$(CIRCUITPY_SERIAL_UART)
+
+# ulab numerics library
+CIRCUITPY_ULAB ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_ULAB=$(CIRCUITPY_ULAB)
+
+# watchdog hardware support
+CIRCUITPY_WATCHDOG ?= 0
+CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG)
+
+# Enabled micropython.native decorator (experimental)
+CIRCUITPY_ENABLE_MPY_NATIVE ?= 0
+CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE)
diff --git a/py/compile.c b/py/compile.c
index 1218aa07e..d5fae0299 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -775,13 +775,22 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
if (attr == MP_QSTR_bytecode) {
*emit_options = MP_EMIT_OPT_BYTECODE;
-#if MICROPY_EMIT_NATIVE
+ // @micropython.native decorator.
} else if (attr == MP_QSTR_native) {
+ // Different from MicroPython: native doesn't raise SyntaxError if native support isn't
+ // compiled, it just passes through the function unmodified.
+ #if MICROPY_EMIT_NATIVE
*emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
+ #else
+ return true;
+ #endif
+ #if MICROPY_EMIT_NATIVE
+ // @micropython.viper decorator.
} else if (attr == MP_QSTR_viper) {
*emit_options = MP_EMIT_OPT_VIPER;
-#endif
+ #endif
#if MICROPY_EMIT_INLINE_ASM
+ // @micropython.asm_thumb decorator.
} else if (attr == ASM_DECORATOR_QSTR) {
*emit_options = MP_EMIT_OPT_ASM;
#endif
@@ -1702,6 +1711,16 @@ STATIC void compile_yield_from(compiler_t *comp) {
}
#if MICROPY_PY_ASYNC_AWAIT
+STATIC bool compile_require_async_context(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ int scope_flags = comp->scope_cur->scope_flags;
+ if(scope_flags & MP_SCOPE_FLAG_GENERATOR) {
+ return true;
+ }
+ compile_syntax_error(comp, (mp_parse_node_t)pns,
+ translate("'async for' or 'async with' outside async function"));
+ return false;
+}
+
STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
EMIT_ARG(load_method, method, false);
EMIT_ARG(call_method, 0, 0, 0);
@@ -1711,6 +1730,10 @@ STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
+ if(!compile_require_async_context(comp, pns)) {
+ return;
+ }
+
qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
uint while_else_label = comp_next_label(comp);
uint try_exception_label = comp_next_label(comp);
@@ -1848,6 +1871,9 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
}
STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ if(!compile_require_async_context(comp, pns)) {
+ return;
+ }
// get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
mp_parse_node_t *nodes;
int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
@@ -3207,7 +3233,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
}
if (pass > MP_PASS_SCOPE) {
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
- for (uint j = 1; j < n_args; j++) {
+ for (int j = 1; j < n_args; j++) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) {
compile_syntax_error(comp, nodes[i], translate("'data' requires integer arguments"));
return;
diff --git a/py/emitglue.c b/py/emitglue.c
index 74bf8ddca..7708689dd 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -142,11 +142,12 @@ 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_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);
break;
#endif
- default:
- // rc->kind should always be set and BYTECODE is the only remaining case
- assert(rc->kind == MP_CODE_BYTECODE);
+ case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table);
break;
+ default:
+ // All other kinds are invalid.
+ mp_raise_RuntimeError(translate("Corrupt raw code"));
}
// check for generator functions and if so wrap in generator object
diff --git a/py/emitnative.c b/py/emitnative.c
index 67b0025c6..60f31d15f 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -58,6 +58,22 @@
#define DEBUG_printf(...) (void)0
#endif
+#ifndef N_X64
+ #define N_X64 (0)
+#endif
+#ifndef N_X86
+ #define N_X86 (0)
+#endif
+#ifndef N_THUMB
+ #define N_THUMB (0)
+#endif
+#ifndef N_ARM
+ #define N_ARM (0)
+#endif
+#ifndef N_XTENSA
+ #define N_XTENSA (0)
+#endif
+
// wrapper around everything in this file
#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA
@@ -443,10 +459,13 @@ STATIC void emit_native_end_pass(emit_t *emit) {
type_sig |= (emit->local_vtype[i] & 0xf) << (i * 4 + 4);
}
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wcast-align"
mp_emit_glue_assign_native(emit->scope->raw_code,
emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
f, f_len, (mp_uint_t*)((byte*)f + emit->const_table_offset),
emit->scope->num_pos_args, emit->scope->scope_flags, type_sig);
+ #pragma GCC diagnostic pop
}
}
diff --git a/py/gc.c b/py/gc.c
index 1f5cd8d01..271bc9462 100755
--- a/py/gc.c
+++ b/py/gc.c
@@ -31,6 +31,8 @@
#include "py/gc.h"
#include "py/runtime.h"
+#include "supervisor/shared/safe_mode.h"
+
#if MICROPY_ENABLE_GC
#if MICROPY_DEBUG_VERBOSE // print debugging info
@@ -51,9 +53,6 @@
// detect untraced object still in use
#define CLEAR_ON_SWEEP (0)
-#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
-#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
-
// ATB = allocation table byte
// 0b00 = FREE -- free block
// 0b01 = HEAD -- head of a chain of blocks
@@ -151,9 +150,13 @@ void gc_init(void *start, void *end) {
#endif
// Set first free ATB index to the start of the heap.
- MP_STATE_MEM(gc_first_free_atb_index) = 0;
+ for (size_t i = 0; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
+ }
+
// Set last free ATB index to the end of the heap.
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
+
// Set the lowest long lived ptr to the end of the heap to start. This will be lowered as long
// lived objects are allocated.
MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void*) PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB));
@@ -174,6 +177,8 @@ void gc_init(void *start, void *end) {
mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex));
#endif
+ MP_STATE_MEM(permanent_pointers) = NULL;
+
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
@@ -182,6 +187,13 @@ void gc_init(void *start, void *end) {
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);
}
+void gc_deinit(void) {
+ // Run any finalizers before we stop using the heap.
+ gc_sweep_all();
+
+ MP_STATE_MEM(gc_pool_start) = 0;
+}
+
void gc_lock(void) {
GC_ENTER();
MP_STATE_MEM(gc_lock_depth)++;
@@ -198,13 +210,6 @@ bool gc_is_locked(void) {
return MP_STATE_MEM(gc_lock_depth) != 0;
}
-// 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 */ \
- )
-
#ifndef TRACE_MARK
#if DEBUG_PRINT
#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr)
@@ -334,6 +339,19 @@ STATIC void gc_sweep(void) {
}
}
+// Mark can handle NULL pointers because it verifies the pointer is within the heap bounds.
+STATIC void gc_mark(void* ptr) {
+ if (VERIFY_PTR(ptr)) {
+ size_t block = BLOCK_FROM_PTR(ptr);
+ if (ATB_GET_KIND(block) == AT_HEAD) {
+ // An unmarked head: mark it, and mark all its children
+ TRACE_MARK(block, ptr);
+ ATB_HEAD_TO_MARK(block);
+ gc_mark_subtree(block);
+ }
+ }
+}
+
void gc_collect_start(void) {
GC_ENTER();
MP_STATE_MEM(gc_lock_depth)++;
@@ -350,6 +368,8 @@ void gc_collect_start(void) {
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_mark(MP_STATE_MEM(permanent_pointers));
+
#if MICROPY_ENABLE_PYSTACK
// Trace root pointers from the Python stack.
ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start);
@@ -357,25 +377,23 @@ void gc_collect_start(void) {
#endif
}
+void gc_collect_ptr(void *ptr) {
+ gc_mark(ptr);
+}
+
void gc_collect_root(void **ptrs, size_t len) {
for (size_t i = 0; i < len; i++) {
void *ptr = ptrs[i];
- if (VERIFY_PTR(ptr)) {
- size_t block = BLOCK_FROM_PTR(ptr);
- if (ATB_GET_KIND(block) == AT_HEAD) {
- // An unmarked head: mark it, and mark all its children
- TRACE_MARK(block, ptr);
- ATB_HEAD_TO_MARK(block);
- gc_mark_subtree(block);
- }
- }
+ gc_mark(ptr);
}
}
void gc_collect_end(void) {
gc_deal_with_stack_overflow();
gc_sweep();
- MP_STATE_MEM(gc_first_free_atb_index) = 0;
+ for (size_t i = 0; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
+ }
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
MP_STATE_MEM(gc_lock_depth)--;
GC_EXIT();
@@ -452,6 +470,10 @@ void gc_info(gc_info_t *info) {
GC_EXIT();
}
+bool gc_alloc_possible(void) {
+ return MP_STATE_MEM(gc_pool_start) != 0;
+}
+
// We place long lived objects at the end of the heap rather than the start. This reduces
// fragmentation by localizing the heap churn to one portion of memory (the start of the heap.)
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
@@ -463,6 +485,10 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
return NULL;
}
+ if (MP_STATE_MEM(gc_pool_start) == 0) {
+ reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
+ }
+
GC_ENTER();
// check if GC is locked
@@ -483,7 +509,6 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
gc_collect();
collected = 1;
GC_ENTER();
- collected = true;
}
#endif
@@ -494,14 +519,16 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
size_t crossover_block = BLOCK_FROM_PTR(MP_STATE_MEM(gc_lowest_long_lived_ptr));
while (keep_looking) {
int8_t direction = 1;
- size_t start = MP_STATE_MEM(gc_first_free_atb_index);
+ size_t bucket = MIN(n_blocks, MICROPY_ATB_INDICES) - 1;
+ size_t first_free = MP_STATE_MEM(gc_first_free_atb_index)[bucket];
+ size_t start = first_free;
if (long_lived) {
direction = -1;
start = MP_STATE_MEM(gc_last_free_atb_index);
}
n_free = 0;
// look for a run of n_blocks available blocks
- for (size_t i = start; keep_looking && MP_STATE_MEM(gc_first_free_atb_index) <= i && i <= MP_STATE_MEM(gc_last_free_atb_index); i += direction) {
+ for (size_t i = start; keep_looking && first_free <= i && i <= MP_STATE_MEM(gc_last_free_atb_index); i += direction) {
byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
// Four ATB states are packed into a single byte.
int j = 0;
@@ -546,22 +573,24 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
// Found free space ending at found_block inclusive.
// Also, set last free ATB index to block after last block we found, for start of
- // next scan. To reduce fragmentation, we only do this if we were looking
- // for a single free block, which guarantees that there are no free blocks
- // before this one. Also, whenever we free or shrink a block we must check
- // if this index needs adjusting (see gc_realloc and gc_free).
+ // next scan. Also, whenever we free or shrink a block we must check if this index needs
+ // adjusting (see gc_realloc and gc_free).
if (!long_lived) {
end_block = found_block;
start_block = found_block - n_free + 1;
- if (n_blocks == 1) {
- MP_STATE_MEM(gc_first_free_atb_index) = (found_block + 1) / BLOCKS_PER_ATB;
+ if (n_blocks < MICROPY_ATB_INDICES) {
+ size_t next_free_atb = (found_block + n_blocks) / BLOCKS_PER_ATB;
+ // Update all atb indices for larger blocks too.
+ for (size_t i = n_blocks - 1; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = next_free_atb;
+ }
}
} else {
start_block = found_block;
end_block = found_block + n_free - 1;
- if (n_blocks == 1) {
- MP_STATE_MEM(gc_last_free_atb_index) = (found_block - 1) / BLOCKS_PER_ATB;
- }
+ // Always update the bounds of the long lived area because we assume it is contiguous. (It
+ // can still be reset by a sweep.)
+ MP_STATE_MEM(gc_last_free_atb_index) = (found_block - 1) / BLOCKS_PER_ATB;
}
#ifdef LOG_HEAP_ACTIVITY
@@ -652,32 +681,42 @@ void gc_free(void *ptr) {
if (ptr == NULL) {
GC_EXIT();
} else {
+ if (MP_STATE_MEM(gc_pool_start) == 0) {
+ reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
+ }
// get the GC block number corresponding to this pointer
assert(VERIFY_PTR(ptr));
- size_t block = BLOCK_FROM_PTR(ptr);
- assert(ATB_GET_KIND(block) == AT_HEAD);
+ size_t start_block = BLOCK_FROM_PTR(ptr);
+ assert(ATB_GET_KIND(start_block) == AT_HEAD);
#if MICROPY_ENABLE_FINALISER
- FTB_CLEAR(block);
+ FTB_CLEAR(start_block);
#endif
- // set the last_free pointer to this block if it's earlier in the heap
- if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_first_free_atb_index)) {
- MP_STATE_MEM(gc_first_free_atb_index) = block / BLOCKS_PER_ATB;
- }
- if (block / BLOCKS_PER_ATB > MP_STATE_MEM(gc_last_free_atb_index)) {
- MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;
- }
-
// free head and all of its tail blocks
- #ifdef LOG_HEAP_ACTIVITY
- gc_log_change(block, 0);
- #endif
+ #ifdef LOG_HEAP_ACTIVITY
+ gc_log_change(start_block, 0);
+ #endif
+ size_t block = start_block;
do {
ATB_ANY_TO_FREE(block);
block += 1;
} while (ATB_GET_KIND(block) == AT_TAIL);
+ // Update the first free pointer for our size only. Not much calls gc_free directly so there
+ // is decent chance we'll want to allocate this size again. By only updating the specific
+ // size we don't risk something smaller fitting in.
+ size_t n_blocks = block - start_block;
+ size_t bucket = MIN(n_blocks, MICROPY_ATB_INDICES) - 1;
+ size_t new_free_atb = start_block / BLOCKS_PER_ATB;
+ if (new_free_atb < MP_STATE_MEM(gc_first_free_atb_index)[bucket]) {
+ MP_STATE_MEM(gc_first_free_atb_index)[bucket] = new_free_atb;
+ }
+ // set the last_free pointer to this block if it's earlier in the heap
+ if (new_free_atb > MP_STATE_MEM(gc_last_free_atb_index)) {
+ MP_STATE_MEM(gc_last_free_atb_index) = new_free_atb;
+ }
+
GC_EXIT();
#if EXTENSIVE_HEAP_PROFILING
@@ -848,11 +887,13 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
}
// set the last_free pointer to end of this block if it's earlier in the heap
- if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_first_free_atb_index)) {
- MP_STATE_MEM(gc_first_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
+ size_t new_free_atb = (block + new_blocks) / BLOCKS_PER_ATB;
+ size_t bucket = MIN(n_blocks - new_blocks, MICROPY_ATB_INDICES) - 1;
+ if (new_free_atb < MP_STATE_MEM(gc_first_free_atb_index)[bucket]) {
+ MP_STATE_MEM(gc_first_free_atb_index)[bucket] = new_free_atb;
}
- if ((block + new_blocks) / BLOCKS_PER_ATB > MP_STATE_MEM(gc_last_free_atb_index)) {
- MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
+ if (new_free_atb > MP_STATE_MEM(gc_last_free_atb_index)) {
+ MP_STATE_MEM(gc_last_free_atb_index) = new_free_atb;
}
GC_EXIT();
@@ -925,6 +966,36 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
}
#endif // Alternative gc_realloc impl
+bool gc_never_free(void *ptr) {
+ // Check to make sure the pointer is on the heap in the first place.
+ if (gc_nbytes(ptr) == 0) {
+ return false;
+ }
+ // Pointers are stored in a linked list where each block is BYTES_PER_BLOCK long and the first
+ // pointer is the next block of pointers.
+ void ** current_reference_block = MP_STATE_MEM(permanent_pointers);
+ while (current_reference_block != NULL) {
+ for (size_t i = 1; i < BYTES_PER_BLOCK / sizeof(void*); i++) {
+ if (current_reference_block[i] == NULL) {
+ current_reference_block[i] = ptr;
+ return true;
+ }
+ }
+ current_reference_block = current_reference_block[0];
+ }
+ void** next_block = gc_alloc(BYTES_PER_BLOCK, false, true);
+ if (next_block == NULL) {
+ return false;
+ }
+ if (MP_STATE_MEM(permanent_pointers) == NULL) {
+ MP_STATE_MEM(permanent_pointers) = next_block;
+ } else {
+ current_reference_block[0] = next_block;
+ }
+ next_block[1] = ptr;
+ return true;
+}
+
void gc_dump_info(void) {
gc_info_t info;
gc_info(&info);
diff --git a/py/gc.h b/py/gc.h
index 64f4b0d17..2a0811f4e 100644
--- a/py/gc.h
+++ b/py/gc.h
@@ -29,9 +29,21 @@
#include <stdint.h>
#include "py/mpconfig.h"
+#include "py/mpstate.h"
#include "py/misc.h"
+#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
+#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
+
+// 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 */ \
+ )
+
void gc_init(void *start, void *end);
+void gc_deinit(void);
// These lock/unlock functions can be nested.
// They can be used to prevent the GC from allocating/freeing.
@@ -42,9 +54,12 @@ bool gc_is_locked(void);
// A given port must implement gc_collect by using the other collect functions.
void gc_collect(void);
void gc_collect_start(void);
+void gc_collect_ptr(void *ptr);
void gc_collect_root(void **ptrs, size_t len);
void gc_collect_end(void);
+// Is the gc heap available?
+bool gc_alloc_possible(void);
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived);
// Use this function to sweep the whole heap and run all finalisers
@@ -56,6 +71,10 @@ bool gc_has_finaliser(const void *ptr);
void *gc_make_long_lived(void *old_ptr);
void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move);
+// Prevents a pointer from ever being freed because it establishes a permanent reference to it. Use
+// very sparingly because it can leak memory.
+bool gc_never_free(void *ptr);
+
typedef struct _gc_info_t {
size_t total;
size_t used;
diff --git a/py/gc_long_lived.c b/py/gc_long_lived.c
index 3c54de7ed..0e94390e9 100755
--- a/py/gc_long_lived.c
+++ b/py/gc_long_lived.c
@@ -27,6 +27,7 @@
#include "py/emitglue.h"
#include "py/gc_long_lived.h"
#include "py/gc.h"
+#include "py/mpstate.h"
mp_obj_fun_bc_t *make_fun_bc_long_lived(mp_obj_fun_bc_t *fun_bc, uint8_t max_depth) {
#ifndef MICROPY_ENABLE_GC
@@ -88,7 +89,7 @@ mp_obj_dict_t *make_dict_long_lived(mp_obj_dict_t *dict, uint8_t max_depth) {
#ifndef MICROPY_ENABLE_GC
return dict;
#endif
- if (dict == NULL || max_depth == 0) {
+ if (dict == NULL || max_depth == 0 || dict == &MP_STATE_VM(dict_main) || dict->map.is_fixed) {
return dict;
}
// Don't recurse unnecessarily. Return immediately if we've already seen this dict.
@@ -125,6 +126,11 @@ mp_obj_t make_obj_long_lived(mp_obj_t obj, uint8_t max_depth){
if (obj == NULL) {
return obj;
}
+ // If not in the GC pool, do nothing. This can happen (at least) when
+ // there are frozen mp_type_bytes objects in ROM.
+ if (!VERIFY_PTR((void *)obj)) {
+ return obj;
+ }
if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) {
mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(obj);
return MP_OBJ_FROM_PTR(make_fun_bc_long_lived(fun_bc, max_depth));
diff --git a/py/lexer.c b/py/lexer.c
index 755fa625b..00cd59bca 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -64,6 +64,12 @@ STATIC bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) {
return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3;
}
+#if MICROPY_COMP_FSTRING_LITERAL
+STATIC bool is_char_or4(mp_lexer_t *lex, byte c1, byte c2, byte c3, byte c4) {
+ return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3 || lex->chr0 == c4;
+}
+#endif
+
STATIC bool is_char_following(mp_lexer_t *lex, byte c) {
return lex->chr1 == c;
}
@@ -107,7 +113,13 @@ STATIC bool is_following_odigit(mp_lexer_t *lex) {
STATIC bool is_string_or_bytes(mp_lexer_t *lex) {
return is_char_or(lex, '\'', '\"')
+#if MICROPY_COMP_FSTRING_LITERAL
+ || (is_char_or4(lex, 'r', 'u', 'b', 'f') && is_char_following_or(lex, '\'', '\"'))
+ || ((is_char_and(lex, 'r', 'f') || is_char_and(lex, 'f', 'r'))
+ && is_char_following_following_or(lex, '\'', '\"'))
+#else
|| (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"'))
+#endif
|| ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))
&& is_char_following_following_or(lex, '\'', '\"'));
}
@@ -121,6 +133,31 @@ STATIC bool is_tail_of_identifier(mp_lexer_t *lex) {
return is_head_of_identifier(lex) || is_digit(lex);
}
+#if MICROPY_COMP_FSTRING_LITERAL
+STATIC void swap_char_banks(mp_lexer_t *lex) {
+ if (lex->vstr_postfix_processing) {
+ lex->chr3 = lex->chr0;
+ lex->chr4 = lex->chr1;
+ lex->chr5 = lex->chr2;
+ lex->chr0 = lex->vstr_postfix.buf[0];
+ lex->chr1 = lex->vstr_postfix.buf[1];
+ lex->chr2 = lex->vstr_postfix.buf[2];
+
+ lex->vstr_postfix_idx = 3;
+ } else {
+ // blindly reset to the "backup" bank when done postfix processing
+ // this restores control to the mp_reader
+ lex->chr0 = lex->chr3;
+ lex->chr1 = lex->chr4;
+ lex->chr2 = lex->chr5;
+ // willfully ignoring setting chr3-5 here - WARNING consider those garbage data now
+
+ vstr_reset(&lex->vstr_postfix);
+ lex->vstr_postfix_idx = 0;
+ }
+}
+#endif
+
STATIC void next_char(mp_lexer_t *lex) {
if (lex->chr0 == '\n') {
// a new line
@@ -136,7 +173,19 @@ STATIC void next_char(mp_lexer_t *lex) {
lex->chr0 = lex->chr1;
lex->chr1 = lex->chr2;
- lex->chr2 = lex->reader.readbyte(lex->reader.data);
+
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (lex->vstr_postfix_processing) {
+ if (lex->vstr_postfix_idx == lex->vstr_postfix.len) {
+ lex->chr2 = '\0';
+ } else {
+ lex->chr2 = lex->vstr_postfix.buf[lex->vstr_postfix_idx++];
+ }
+ } else
+#endif
+ {
+ lex->chr2 = lex->reader.readbyte(lex->reader.data);
+ }
if (lex->chr1 == '\r') {
// CR is a new line, converted to LF
@@ -151,6 +200,13 @@ STATIC void next_char(mp_lexer_t *lex) {
if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') {
lex->chr2 = '\n';
}
+
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (lex->vstr_postfix_processing && lex->chr0 == '\0') {
+ lex->vstr_postfix_processing = false;
+ swap_char_banks(lex);
+ }
+#endif
}
STATIC void indent_push(mp_lexer_t *lex, size_t indent) {
@@ -270,7 +326,7 @@ STATIC bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) {
return true;
}
-STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
+STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) {
// get first quoting character
char quote_char = '\'';
if (is_char(lex, '\"')) {
@@ -291,15 +347,71 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
}
size_t n_closing = 0;
+#if MICROPY_COMP_FSTRING_LITERAL
+ bool in_expression = false;
+ bool expression_eat = true;
+#endif
+
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
if (is_char(lex, quote_char)) {
n_closing += 1;
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
} else {
n_closing = 0;
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (is_fstring && is_char(lex, '{')) {
+ vstr_add_char(&lex->vstr, CUR_CHAR(lex));
+ in_expression = !in_expression;
+ expression_eat = in_expression;
+
+ if (lex->vstr_postfix.len == 0) {
+ vstr_add_str(&lex->vstr_postfix, ".format(");
+ }
+
+ next_char(lex);
+ continue;
+ }
+
+ if (is_fstring && is_char(lex, '}')) {
+ vstr_add_char(&lex->vstr, CUR_CHAR(lex));
+
+ if (in_expression) {
+ in_expression = false;
+ vstr_add_char(&lex->vstr_postfix, ',');
+ }
+
+ next_char(lex);
+ continue;
+ }
+
+ if (in_expression) {
+ // throw errors for illegal chars inside f-string expressions
+ if (is_char(lex, '#')) {
+ lex->tok_kind = MP_TOKEN_FSTRING_COMMENT;
+ return;
+ } else if (is_char(lex, '\\')) {
+ lex->tok_kind = MP_TOKEN_FSTRING_BACKSLASH;
+ return;
+ } else if (is_char(lex, ':')) {
+ expression_eat = false;
+ }
+
+ unichar c = CUR_CHAR(lex);
+ if (expression_eat) {
+ vstr_add_char(&lex->vstr_postfix, c);
+ } else {
+ vstr_add_char(&lex->vstr, c);
+ }
+
+ next_char(lex);
+ continue;
+ }
+#endif
+
if (is_char(lex, '\\')) {
next_char(lex);
unichar c = CUR_CHAR(lex);
+
if (is_raw) {
// raw strings allow escaping of quotes, but the backslash is also emitted
vstr_add_char(&lex->vstr, '\\');
@@ -430,6 +542,15 @@ STATIC bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) {
}
void mp_lexer_to_next(mp_lexer_t *lex) {
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (lex->vstr_postfix.len && !lex->vstr_postfix_processing) {
+ // end format call injection
+ vstr_add_char(&lex->vstr_postfix, ')');
+ lex->vstr_postfix_processing = true;
+ swap_char_banks(lex);
+ }
+#endif
+
// start new token text
vstr_reset(&lex->vstr);
@@ -481,10 +602,19 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
// MP_TOKEN_END is used to indicate that this is the first string token
lex->tok_kind = MP_TOKEN_END;
+#if MICROPY_COMP_FSTRING_LITERAL
+ bool saw_normal = false, saw_fstring = false;
+#endif
+
// Loop to accumulate string/bytes literals
do {
// parse type codes
bool is_raw = false;
+#if MICROPY_COMP_FSTRING_LITERAL
+ bool is_fstring = false;
+#else
+ const bool is_fstring = false;
+#endif
mp_token_kind_t kind = MP_TOKEN_STRING;
int n_char = 0;
if (is_char(lex, 'u')) {
@@ -503,7 +633,33 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
kind = MP_TOKEN_BYTES;
n_char = 2;
}
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (is_char_following(lex, 'f')) {
+ lex->tok_kind = MP_TOKEN_FSTRING_RAW;
+ break;
+ }
+ } else if (is_char(lex, 'f')) {
+ if (is_char_following(lex, 'r')) {
+ lex->tok_kind = MP_TOKEN_FSTRING_RAW;
+ break;
+ }
+ n_char = 1;
+ is_fstring = true;
+#endif
+ }
+
+#if MICROPY_COMP_FSTRING_LITERAL
+ if (is_fstring) {
+ saw_fstring = true;
+ } else {
+ saw_normal = true;
+ }
+
+ if (saw_fstring && saw_normal) {
+ // Can't concatenate f-string with normal string
+ break;
}
+#endif
// Set or check token kind
if (lex->tok_kind == MP_TOKEN_END) {
@@ -522,13 +678,12 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
}
// Parse the literal
- parse_string_literal(lex, is_raw);
+ parse_string_literal(lex, is_raw, is_fstring);
// Skip whitespace so we can check if there's another string following
skip_whitespace(lex, true);
} while (is_string_or_bytes(lex));
-
} else if (is_head_of_identifier(lex)) {
lex->tok_kind = MP_TOKEN_NAME;
@@ -682,6 +837,9 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {
lex->num_indent_level = 1;
lex->indent_level = m_new(uint16_t, lex->alloc_indent_level);
vstr_init(&lex->vstr, 32);
+#if MICROPY_COMP_FSTRING_LITERAL
+ vstr_init(&lex->vstr_postfix, 0);
+#endif
// store sentinel for first indentation level
lex->indent_level[0] = 0;
diff --git a/py/lexer.h b/py/lexer.h
index a29709107..a3eaa2a7e 100644
--- a/py/lexer.h
+++ b/py/lexer.h
@@ -44,6 +44,14 @@ typedef enum _mp_token_kind_t {
MP_TOKEN_INVALID,
MP_TOKEN_DEDENT_MISMATCH,
MP_TOKEN_LONELY_STRING_OPEN,
+#if MICROPY_COMP_FSTRING_LITERAL
+ MP_TOKEN_FSTRING_BACKSLASH,
+ MP_TOKEN_FSTRING_COMMENT,
+ MP_TOKEN_FSTRING_UNCLOSED,
+ MP_TOKEN_FSTRING_UNOPENED,
+ MP_TOKEN_FSTRING_EMPTY_EXP,
+ MP_TOKEN_FSTRING_RAW,
+#endif
MP_TOKEN_NEWLINE,
MP_TOKEN_INDENT,
@@ -150,6 +158,9 @@ typedef struct _mp_lexer_t {
mp_reader_t reader; // stream source
unichar chr0, chr1, chr2; // current cached characters from source
+#if MICROPY_COMP_FSTRING_LITERAL
+ unichar chr3, chr4, chr5; // current cached characters from alt source
+#endif
size_t line; // current source line
size_t column; // current source column
@@ -165,6 +176,11 @@ typedef struct _mp_lexer_t {
size_t tok_column; // token source column
mp_token_kind_t tok_kind; // token kind
vstr_t vstr; // token data
+#if MICROPY_COMP_FSTRING_LITERAL
+ vstr_t vstr_postfix; // postfix to apply to string
+ bool vstr_postfix_processing;
+ uint16_t vstr_postfix_idx;
+#endif
} mp_lexer_t;
mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader);
diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py
new file mode 100644
index 000000000..18d327f00
--- /dev/null
+++ b/py/makemoduledefs.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+
+# This pre-processor parses provided objects' c files for
+# MP_REGISTER_MODULE(module_name, obj_module, enabled_define)
+# These are used to generate a header with the required entries for
+# "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c
+
+from __future__ import print_function
+
+import re
+import os
+import argparse
+
+
+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.
+
+ :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
+ :return: str path to c file or None
+ """
+ c_file = None
+ relative_c_file = os.path.splitext(obj_file)[0] + ".c"
+ 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):
+ c_file = possible_c_file
+ break
+
+ return c_file
+
+
+def find_module_registrations(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)]
+ """
+ global pattern
+
+ if c_file is None:
+ # No c file to match the object file, skip
+ return set()
+
+ with open(c_file) 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.
+
+ :param List[(module_name, obj_module, enabled_define)] modules: module defs
+ :return: None
+ """
+
+ # Print header file for all external modules.
+ mod_defs = []
+ print("// Automatically generated by makemoduledefs.py.\n")
+ 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("\n#define MICROPY_REGISTERED_MODULES \\")
+
+ for mod_def in mod_defs:
+ print(" {mod_def} \\".format(mod_def=mod_def))
+
+ print("// MICROPY_REGISTERED_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")
+ args = parser.parse_args()
+
+ vpath = [p.strip() for p in args.vpath.split(',')]
+
+ modules = set()
+ for obj_file in args.files:
+ c_file = find_c_file(obj_file, vpath)
+ modules |= find_module_registrations(c_file)
+
+ generate_module_table_header(sorted(modules))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 5b5ec1c37..df2c687e5 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -1,7 +1,10 @@
"""
Process raw qstr file and output qstr data with length, hash and data bytes.
-This script works with Python 2.6, 2.7, 3.3 and 3.4.
+This script works with Python 2.7, 3.3 and 3.4.
+
+For documentation about the format of compressed translated strings, see
+supervisor/shared/translate.h
"""
from __future__ import print_function
@@ -103,14 +106,10 @@ def compute_huffman_coding(translations, qstrs, compression_filename):
# go through each qstr and print it out
for _, _, qstr in qstrs.values():
all_strings.append(qstr)
- all_strings_concat = "".join(all_strings).encode("utf-8")
+ all_strings_concat = "".join(all_strings)
counts = collections.Counter(all_strings_concat)
- # add other values
- for i in range(256):
- if i not in counts:
- counts[i] = 0
cb = huffman.codebook(counts.items())
- values = bytearray()
+ values = []
length_count = {}
renumbered = 0
last_l = None
@@ -124,30 +123,49 @@ def compute_huffman_coding(translations, qstrs, compression_filename):
if last_l:
renumbered <<= (l - last_l)
canonical[ch] = '{0:0{width}b}'.format(renumbered, width=l)
- if chr(ch) in C_ESCAPES:
- s = C_ESCAPES[chr(ch)]
- else:
- s = chr(ch)
- print("//", ch, s, counts[ch], canonical[ch], renumbered)
+ s = C_ESCAPES.get(ch, ch)
+ print("//", ord(ch), s, counts[ch], canonical[ch], renumbered)
renumbered += 1
last_l = l
lengths = bytearray()
- for i in range(1, max(length_count) + 1):
+ print("// length count", length_count)
+ for i in range(1, max(length_count) + 2):
lengths.append(length_count.get(i, 0))
+ print("// values", values, "lengths", len(lengths), lengths)
+ print("// estimated total memory size", len(lengths) + 2*len(values) + sum(len(cb[u]) for u in all_strings_concat))
print("//", values, lengths)
+ values_type = "uint16_t" if max(ord(u) for u in values) > 255 else "uint8_t"
+ max_translation_encoded_length = max(len(translation.encode("utf-8")) for original,translation in translations)
with open(compression_filename, "w") as f:
f.write("const uint8_t lengths[] = {{ {} }};\n".format(", ".join(map(str, lengths))))
- f.write("const uint8_t values[256] = {{ {} }};\n".format(", ".join(map(str, values))))
+ f.write("const {} values[] = {{ {} }};\n".format(values_type, ", ".join(str(ord(u)) for u in values)))
+ f.write("#define compress_max_length_bits ({})\n".format(max_translation_encoded_length.bit_length()))
return values, lengths
-def decompress(encoding_table, length, encoded):
+def decompress(encoding_table, encoded, encoded_length_bits):
values, lengths = encoding_table
- #print(l, encoded)
- dec = bytearray(length)
+ dec = []
this_byte = 0
this_bit = 7
b = encoded[this_byte]
- for i in range(length):
+ bits = 0
+ for i in range(encoded_length_bits):
+ bits <<= 1
+ if 0x80 & b:
+ bits |= 1
+
+ b <<= 1
+ if this_bit == 0:
+ this_bit = 7
+ this_byte += 1
+ if this_byte < len(encoded):
+ b = encoded[this_byte]
+ else:
+ this_bit -= 1
+ length = bits
+
+ i = 0
+ while i < length:
bits = 0
bit_length = 0
max_code = lengths[0]
@@ -173,18 +191,32 @@ def decompress(encoding_table, length, encoded):
searched_length += lengths[bit_length]
v = values[searched_length + bits - max_code]
- dec[i] = v
- return dec
+ i += len(v.encode('utf-8'))
+ dec.append(v)
+ return ''.join(dec)
-def compress(encoding_table, decompressed):
- if not isinstance(decompressed, bytes):
+def compress(encoding_table, decompressed, encoded_length_bits, len_translation_encoded):
+ if not isinstance(decompressed, str):
raise TypeError()
values, lengths = encoding_table
- enc = bytearray(len(decompressed))
+ enc = bytearray(len(decompressed) * 3)
#print(decompressed)
#print(lengths)
current_bit = 7
current_byte = 0
+
+ code = len_translation_encoded
+ bits = encoded_length_bits+1
+ for i in range(bits - 1, 0, -1):
+ if len_translation_encoded & (1 << (i - 1)):
+ enc[current_byte] |= 1 << current_bit
+ if current_bit == 0:
+ current_bit = 7
+ #print("packed {0:0{width}b}".format(enc[current_byte], width=8))
+ current_byte += 1
+ else:
+ current_bit -= 1
+
for c in decompressed:
#print()
#print("char", c, values.index(c))
@@ -227,6 +259,8 @@ def compress(encoding_table, decompressed):
current_bit -= 1
if current_bit != 7:
current_byte += 1
+ if current_byte > len(decompressed):
+ print("Note: compression increased length", repr(decompressed), len(decompressed), current_byte, file=sys.stderr)
return enc[:current_byte]
def qstr_escape(qst):
@@ -343,14 +377,17 @@ def print_qstr_data(encoding_table, qcfgs, qstrs, i18ns):
total_text_size = 0
total_text_compressed_size = 0
+ max_translation_encoded_length = max(len(translation.encode("utf-8")) for original, translation in i18ns)
+ encoded_length_bits = max_translation_encoded_length.bit_length()
for original, translation in i18ns:
translation_encoded = translation.encode("utf-8")
- compressed = compress(encoding_table, translation_encoded)
+ compressed = compress(encoding_table, translation, encoded_length_bits, len(translation_encoded))
total_text_compressed_size += len(compressed)
- decompressed = decompress(encoding_table, len(translation_encoded), compressed).decode("utf-8")
+ decompressed = decompress(encoding_table, compressed, encoded_length_bits)
+ assert decompressed == translation
for c in C_ESCAPES:
decompressed = decompressed.replace(c, C_ESCAPES[c])
- print("TRANSLATION(\"{}\", {}, {{ {} }}) // {}".format(original, len(translation_encoded)+1, ", ".join(["0x{:02x}".format(x) for x in compressed]), decompressed))
+ print("TRANSLATION(\"{}\", {}) // {}".format(original, ", ".join(["{:d}".format(x) for x in compressed]), decompressed))
total_text_size += len(translation.encode("utf-8"))
print()
@@ -386,6 +423,7 @@ if __name__ == "__main__":
qcfgs, qstrs, i18ns = parse_input_headers(args.infiles)
if args.translation:
+ i18ns = sorted(i18ns)
translations = translate(args.translation, i18ns)
encoding_table = compute_huffman_coding(translations, qstrs, args.compression_filename)
print_qstr_data(encoding_table, qcfgs, qstrs, translations)
diff --git a/py/map.c b/py/map.c
index 6abf4853f..57c11dbc9 100644
--- a/py/map.c
+++ b/py/map.c
@@ -33,6 +33,8 @@
#include "py/misc.h"
#include "py/runtime.h"
+#include "supervisor/linker.h"
+
#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
#else // don't print debugging info
@@ -143,7 +145,7 @@ STATIC void mp_map_rehash(mp_map_t *map) {
// - returns slot, with key non-null and value=MP_OBJ_NULL if it was added
// MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour:
// - returns NULL if not found, else the slot if was found in with key null and value non-null
-mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
+mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
// If the map is a fixed array then we must only be called for a lookup
assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP);
diff --git a/py/mkrules.mk b/py/mkrules.mk
index aa94ba412..13a73b90e 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -20,12 +20,12 @@ endif
# can be located. By following this scheme, it allows a single build rule
# to be used to compile all .c files.
-vpath %.S . $(TOP)
+vpath %.S . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.o: %.S
$(STEPECHO) "CC $<"
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
-vpath %.s . $(TOP)
+vpath %.s . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.o: %.s
$(STEPECHO) "AS $<"
$(Q)$(AS) -o $@ $<
@@ -42,7 +42,7 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
$(RM) -f $(@:.o=.d)
endef
-vpath %.c . $(TOP)
+vpath %.c . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.o: %.c
$(call compile_c)
@@ -56,7 +56,7 @@ $(BUILD)/%.o: %.c
QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp
-vpath %.c . $(TOP)
+vpath %.c . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.pp: %.c
$(STEPECHO) "PreProcess $<"
@@ -145,7 +145,7 @@ $(PROG): $(OBJ)
# Do not pass COPT here - it's *C* compiler optimizations. For example,
# we may want to compile using Thumb, but link with non-Thumb libc.
$(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS)
-ifndef DEBUG
+ifdef STRIP_CIRCUITPYTHON
$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
endif
$(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index fc7ec24c7..e764f1987 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -371,10 +371,11 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_sep, ARG_end, ARG_file };
+ enum { ARG_sep, ARG_end, ARG_flush, ARG_file };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} },
{ MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} },
+ { MP_QSTR_flush, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
{ MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} },
#endif
@@ -414,6 +415,9 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map
}
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
mp_stream_write_adaptor(print.data, end_data, u.len[1]);
+ if (u.args[ARG_flush].u_bool) {
+ mp_stream_flush(MP_OBJ_FROM_PTR(print.data));
+ }
#else
mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0);
#endif
@@ -451,13 +455,13 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) {
return o_in;
}
- #if !MICROPY_PY_BUILTINS_ROUND_INT
- mp_raise_NotImplementedError(NULL);
- #else
mp_int_t num_dig = mp_obj_get_int(args[1]);
if (num_dig >= 0) {
return o_in;
}
+ #if !MICROPY_PY_BUILTINS_ROUND_INT
+ mp_raise_NotImplementedError(NULL);
+ #else
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));
@@ -516,7 +520,7 @@ STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t
if (n_args > 1) {
mp_raise_TypeError(translate("must use keyword argument for key function"));
}
- mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args);
+ mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, args, NULL);
mp_obj_list_sort(1, &self, kwargs);
return self;
@@ -718,6 +722,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_KeyError), MP_ROM_PTR(&mp_type_KeyError) },
{ MP_ROM_QSTR(MP_QSTR_LookupError), MP_ROM_PTR(&mp_type_LookupError) },
{ MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_MemoryError) },
+ { MP_ROM_QSTR(MP_QSTR_MpyError), MP_ROM_PTR(&mp_type_MpyError) },
{ MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) },
{ MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) },
{ MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) },
diff --git a/py/modio.c b/py/modio.c
index 9b09de96e..17840a6d8 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -46,11 +46,11 @@ STATIC const mp_obj_type_t mp_type_iobase;
STATIC mp_obj_base_t iobase_singleton = {&mp_type_iobase};
-STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type;
(void)n_args;
- (void)n_kw;
(void)args;
+ (void)kw_args;
return MP_OBJ_FROM_PTR(&iobase_singleton);
}
@@ -90,6 +90,7 @@ STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, in
}
STATIC const mp_stream_p_t iobase_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = iobase_read,
.write = iobase_write,
.ioctl = iobase_ioctl,
@@ -113,8 +114,8 @@ typedef struct _mp_obj_bufwriter_t {
byte buf[0];
} mp_obj_bufwriter_t;
-STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 2, 2, false);
+STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 2, 2, false);
size_t alloc = mp_obj_get_int(args[1]);
mp_obj_bufwriter_t *o = m_new_obj_var(mp_obj_bufwriter_t, byte, alloc);
o->base.type = type;
@@ -185,6 +186,7 @@ STATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table);
STATIC const mp_stream_p_t bufwriter_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.write = bufwriter_write,
};
diff --git a/py/modstruct.c b/py/modstruct.c
index 3f1b2f8b8..a238d3935 100644
--- a/py/modstruct.c
+++ b/py/modstruct.c
@@ -97,7 +97,10 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) {
total_cnt += 1;
size += cnt;
} else {
- total_cnt += cnt;
+ // Pad bytes are skipped and don't get included in the item count.
+ if (*fmt != 'x') {
+ total_cnt += cnt;
+ }
mp_uint_t align;
size_t sz = mp_binary_get_size(fmt_type, *fmt, &align);
while (cnt--) {
@@ -166,7 +169,10 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
} else {
while (cnt--) {
item = mp_binary_get_val(fmt_type, *fmt, &p);
- res->items[i++] = item;
+ // Pad bytes ('x') are just skipped.
+ if (*fmt != 'x') {
+ res->items[i++] = item;
+ }
}
}
fmt++;
@@ -204,7 +210,11 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c
} else {
// If we run out of args then we just finish; CPython would raise struct.error
while (cnt-- && i < n_args) {
- mp_binary_set_val(fmt_type, *fmt, args[i++], &p);
+ mp_binary_set_val(fmt_type, *fmt, args[i], &p);
+ // Pad bytes don't have a corresponding argument.
+ if (*fmt != 'x') {
+ i++;
+ }
}
}
fmt++;
diff --git a/py/moduerrno.c b/py/moduerrno.c
index c1feafaa1..3be5adba1 100644
--- a/py/moduerrno.c
+++ b/py/moduerrno.c
@@ -84,7 +84,11 @@ STATIC const mp_obj_dict_t errorcode_dict = {
#endif
STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = {
+#if CIRCUITPY
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_errno) },
+#else
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) },
+#endif
#if MICROPY_PY_UERRNO_ERRORCODE
{ MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) },
#endif
@@ -151,9 +155,10 @@ const char *mp_common_errno_to_str(mp_obj_t errno_val, char *buf, size_t len) {
case EEXIST: desc = translate("File exists"); break;
case ENODEV: desc = translate("Unsupported operation"); break;
case EINVAL: desc = translate("Invalid argument"); break;
+ case ENOSPC: desc = translate("No space left on device"); break;
case EROFS: desc = translate("Read-only filesystem"); break;
}
- if (desc != NULL && desc->length <= len) {
+ if (desc != NULL && decompress_length(desc) <= len) {
decompress(desc, buf);
return buf;
}
diff --git a/py/mpconfig.h b/py/mpconfig.h
index a846f6a25..513f04f6e 100755
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -45,6 +45,11 @@
#include <mpconfigport.h>
#endif
+// Is this a CircuitPython build?
+#ifndef CIRCUITPY
+#define CIRCUITPY 0
+#endif
+
// Any options not explicitly set in mpconfigport.h will get default
// values below.
@@ -239,6 +244,14 @@
#define alloca(x) m_malloc(x)
#endif
+// Number of atb indices to cache. Allocations of fewer blocks will be faster
+// because the search will be accelerated by the index cache. This only applies
+// to short lived allocations because we assume the long lived allocations are
+// contiguous.
+#ifndef MICROPY_ATB_INDICES
+#define MICROPY_ATB_INDICES (8)
+#endif
+
/*****************************************************************************/
/* MicroPython emitters */
@@ -364,6 +377,11 @@
#define MICROPY_COMP_RETURN_IF_EXPR (0)
#endif
+// Whether to include parsing of f-string literals
+#ifndef MICROPY_COMP_FSTRING_LITERAL
+#define MICROPY_COMP_FSTRING_LITERAL (1)
+#endif
+
/*****************************************************************************/
/* Internal debugging stuff */
@@ -1160,10 +1178,26 @@ typedef double mp_float_t;
#define MICROPY_PY_UJSON (0)
#endif
+#ifndef CIRCUITPY_ULAB
+#define CIRCUITPY_ULAB (0)
+#endif
+
#ifndef MICROPY_PY_URE
#define MICROPY_PY_URE (0)
#endif
+#ifndef MICROPY_PY_URE_MATCH_GROUPS
+#define MICROPY_PY_URE_MATCH_GROUPS (0)
+#endif
+
+#ifndef MICROPY_PY_URE_MATCH_SPAN_START_END
+#define MICROPY_PY_URE_MATCH_SPAN_START_END (0)
+#endif
+
+#ifndef MICROPY_PY_URE_SUB
+#define MICROPY_PY_URE_SUB (0)
+#endif
+
#ifndef MICROPY_PY_UHEAPQ
#define MICROPY_PY_UHEAPQ (0)
#endif
@@ -1423,6 +1457,15 @@ typedef double mp_float_t;
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
#endif
+// To annotate that code is unreachable
+#ifndef MP_UNREACHABLE
+#if defined(__GNUC__)
+#define MP_UNREACHABLE __builtin_unreachable();
+#else
+#define MP_UNREACHABLE for (;;);
+#endif
+#endif
+
#ifndef MP_HTOBE16
#if MP_ENDIANNESS_LITTLE
# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) ))
diff --git a/py/mpstate.c b/py/mpstate.c
index 6ce64adfd..32f1d60a5 100644
--- a/py/mpstate.c
+++ b/py/mpstate.c
@@ -25,9 +25,10 @@
*/
#include "py/mpstate.h"
+#include "supervisor/linker.h"
#if MICROPY_DYNAMIC_COMPILER
mp_dynamic_compiler_t mp_dynamic_compiler = {0};
#endif
-mp_state_ctx_t mp_state_ctx;
+mp_state_ctx_t PLACE_IN_DTCM_BSS(mp_state_ctx);
diff --git a/py/mpstate.h b/py/mpstate.h
index eef8696d3..a5815776a 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -92,7 +92,7 @@ typedef struct _mp_state_mem_t {
size_t gc_alloc_threshold;
#endif
- size_t gc_first_free_atb_index;
+ size_t gc_first_free_atb_index[MICROPY_ATB_INDICES];
size_t gc_last_free_atb_index;
#if MICROPY_PY_GC_COLLECT_RETVAL
@@ -103,6 +103,8 @@ typedef struct _mp_state_mem_t {
// This is a global mutex used to make the GC thread-safe.
mp_thread_mutex_t gc_mutex;
#endif
+
+ void** permanent_pointers;
} mp_state_mem_t;
// This structure hold runtime and VM information. It includes a section
diff --git a/py/nlr.h b/py/nlr.h
index 802f5f39a..1b95002d3 100644
--- a/py/nlr.h
+++ b/py/nlr.h
@@ -36,33 +36,45 @@
// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch
#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP
-#define MICROPY_NLR_SETJMP (0)
// A lot of nlr-related things need different treatment on Windows
-#if defined(_WIN32) || defined(__CYGWIN__)
-#define MICROPY_NLR_OS_WINDOWS 1
-#else
-#define MICROPY_NLR_OS_WINDOWS 0
-#endif
-#if defined(__i386__)
- #define MICROPY_NLR_X86 (1)
- #define MICROPY_NLR_NUM_REGS (6)
-#elif defined(__x86_64__)
- #define MICROPY_NLR_X64 (1)
- #if MICROPY_NLR_OS_WINDOWS
- #define MICROPY_NLR_NUM_REGS (10)
+ #if defined(_WIN32) || defined(__CYGWIN__)
+ #define MICROPY_NLR_OS_WINDOWS 1
#else
- #define MICROPY_NLR_NUM_REGS (8)
+ #define MICROPY_NLR_OS_WINDOWS 0
#endif
-#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
- #define MICROPY_NLR_THUMB (1)
- #define MICROPY_NLR_NUM_REGS (10)
-#elif defined(__xtensa__)
- #define MICROPY_NLR_XTENSA (1)
- #define MICROPY_NLR_NUM_REGS (10)
-#else
- #define MICROPY_NLR_SETJMP (1)
+ #if defined(__i386__)
+ #define MICROPY_NLR_X86 (1)
+ #define MICROPY_NLR_NUM_REGS (6)
+ #elif defined(__x86_64__)
+ #define MICROPY_NLR_X64 (1)
+ #if MICROPY_NLR_OS_WINDOWS
+ #define MICROPY_NLR_NUM_REGS (10)
+ #else
+ #define MICROPY_NLR_NUM_REGS (8)
+ #endif
+ #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
+ #define MICROPY_NLR_THUMB (1)
+ #if defined(__SOFTFP__)
+ #define MICROPY_NLR_NUM_REGS (10)
+ #else
+ // With hardware FP registers s16-s31 are callee save so in principle
+ // should be saved and restored by the NLR code. gcc only uses s16-s21
+ // so only save/restore those as an optimisation.
+ #define MICROPY_NLR_NUM_REGS (10 + 6)
+ #endif
+ #elif defined(__xtensa__)
+ #define MICROPY_NLR_XTENSA (1)
+ #define MICROPY_NLR_NUM_REGS (10)
+ #else
+ #define MICROPY_NLR_SETJMP (1)
//#warning "No native NLR support for this arch, using setjmp implementation"
+ #endif
#endif
+
+// If MICROPY_NLR_SETJMP is not defined above - define/disable it here
+
+#if !defined(MICROPY_NLR_SETJMP)
+ #define MICROPY_NLR_SETJMP (0)
#endif
#if MICROPY_NLR_SETJMP
diff --git a/py/nlrthumb.c b/py/nlrthumb.c
index 69d3f868a..056aa358e 100644
--- a/py/nlrthumb.c
+++ b/py/nlrthumb.c
@@ -63,6 +63,11 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
"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
@@ -118,6 +123,11 @@ NORETURN void nlr_jump(void *val) {
"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
@@ -127,11 +137,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- #if defined(__GNUC__)
- __builtin_unreachable();
- #else
- for (;;); // needed to silence compiler warning
- #endif
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_THUMB
diff --git a/py/nlrx64.c b/py/nlrx64.c
index 9b2b22c22..569ad84fb 100644
--- a/py/nlrx64.c
+++ b/py/nlrx64.c
@@ -108,7 +108,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_X64
diff --git a/py/nlrx86.c b/py/nlrx86.c
index 4900a4c0d..6fbbe4432 100644
--- a/py/nlrx86.c
+++ b/py/nlrx86.c
@@ -100,7 +100,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_X86
diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c
index d66c7a9a7..564035004 100644
--- a/py/nlrxtensa.c
+++ b/py/nlrxtensa.c
@@ -77,7 +77,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_XTENSA
diff --git a/py/obj.c b/py/obj.c
index 35a7519bb..4fa2032dc 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -33,10 +33,13 @@
#include "py/objtype.h"
#include "py/objint.h"
#include "py/objstr.h"
+#include "py/qstr.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/stream.h" // for mp_obj_print
+#include "supervisor/linker.h"
+#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
@@ -61,6 +64,9 @@ 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();
+ #ifdef RUN_BACKGROUND_TASKS
+ RUN_BACKGROUND_TASKS;
+ #endif
#ifndef NDEBUG
if (o_in == MP_OBJ_NULL) {
mp_print_str(print, "(nil)");
@@ -81,24 +87,24 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
// helper function to print an exception with traceback
void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
- if (mp_obj_is_exception_instance(exc)) {
+ if (mp_obj_is_exception_instance(exc) && stack_ok()) {
size_t n, *values;
mp_obj_exception_get_traceback(exc, &n, &values);
if (n > 0) {
assert(n % 3 == 0);
// Decompress the format strings
const compressed_string_t* traceback = translate("Traceback (most recent call last):\n");
- char decompressed[traceback->length];
+ char decompressed[decompress_length(traceback)];
decompress(traceback, decompressed);
#if MICROPY_ENABLE_SOURCE_LINE
const compressed_string_t* frame = translate(" File \"%q\", line %d");
#else
const compressed_string_t* frame = translate(" File \"%q\"");
#endif
- char decompressed_frame[frame->length];
+ char decompressed_frame[decompress_length(frame)];
decompress(frame, decompressed_frame);
const compressed_string_t* block_fmt = translate(", in %q\n");
- char decompressed_block[block_fmt->length];
+ char decompressed_block[decompress_length(block_fmt)];
decompress(block_fmt, decompressed_block);
// Print the traceback
@@ -123,7 +129,7 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
mp_print_str(print, "\n");
}
-bool mp_obj_is_true(mp_obj_t arg) {
+bool PLACE_IN_ITCM(mp_obj_is_true)(mp_obj_t arg) {
if (arg == mp_const_false) {
return 0;
} else if (arg == mp_const_true) {
@@ -484,12 +490,14 @@ 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);
+
if (type->subscr != NULL) {
mp_obj_t ret = type->subscr(base, index, value);
+ // May have called port specific C code. Make sure it didn't mess up the heap.
+ assert_heap_ok();
if (ret != MP_OBJ_NULL) {
return ret;
}
- // TODO: call base classes here?
}
if (value == MP_OBJ_NULL) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
@@ -527,6 +535,36 @@ mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) {
return self;
}
+typedef struct {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ mp_obj_t obj;
+ mp_int_t cur;
+} mp_obj_generic_it_t;
+
+STATIC mp_obj_t generic_it_iternext(mp_obj_t self_in) {
+ mp_obj_generic_it_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_type_t *type = mp_obj_get_type(self->obj);
+ mp_obj_t current_length = type->unary_op(MP_UNARY_OP_LEN, self->obj);
+ if (self->cur < MP_OBJ_SMALL_INT_VALUE(current_length)) {
+ mp_obj_t o_out = type->subscr(self->obj, MP_OBJ_NEW_SMALL_INT(self->cur), MP_OBJ_SENTINEL);
+ self->cur += 1;
+ return o_out;
+ } else {
+ return MP_OBJ_STOP_ITERATION;
+ }
+}
+
+mp_obj_t mp_obj_new_generic_iterator(mp_obj_t obj, mp_obj_iter_buf_t *iter_buf) {
+ assert(sizeof(mp_obj_generic_it_t) <= sizeof(mp_obj_iter_buf_t));
+ mp_obj_generic_it_t *o = (mp_obj_generic_it_t*)iter_buf;
+ o->base.type = &mp_type_polymorph_iter;
+ o->iternext = generic_it_iternext;
+ o->obj = obj;
+ o->cur = 0;
+ return MP_OBJ_FROM_PTR(o);
+}
+
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);
if (type->buffer_p.get_buffer == NULL) {
diff --git a/py/obj.h b/py/obj.h
index 8b6772873..fa315d12f 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -338,6 +338,13 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name}
#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name}
+// Declare a module as a builtin, processed by makemoduledefs.py
+// param module_name: MP_QSTR_<module name>
+// param obj_module: mp_obj_module_t instance
+// prarm enabled_define: used as `#if (enabled_define) around entry`
+
+#define MP_REGISTER_MODULE(module_name, obj_module, enabled_define)
+
// Underlying map/hash table implementation (not dict object or map function)
typedef struct _mp_map_elem_t {
@@ -432,7 +439,7 @@ typedef struct _mp_obj_iter_buf_t {
#define MP_OBJ_ITER_BUF_NSLOTS ((sizeof(mp_obj_iter_buf_t) + sizeof(mp_obj_t) - 1) / sizeof(mp_obj_t))
typedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind);
-typedef mp_obj_t (*mp_make_new_fun_t)(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
+typedef mp_obj_t (*mp_make_new_fun_t)(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_unary_op_fun_t)(mp_unary_op_t op, mp_obj_t);
typedef mp_obj_t (*mp_binary_op_fun_t)(mp_binary_op_t op, mp_obj_t, mp_obj_t);
@@ -592,6 +599,7 @@ extern const mp_obj_type_t mp_type_ReloadException;
extern const mp_obj_type_t mp_type_KeyError;
extern const mp_obj_type_t mp_type_LookupError;
extern const mp_obj_type_t mp_type_MemoryError;
+extern const mp_obj_type_t mp_type_MpyError;
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;
@@ -639,7 +647,9 @@ 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_of_zeros(size_t len);
mp_obj_t mp_obj_new_bytearray(size_t n, void *items);
+mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n);
mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items);
#if MICROPY_PY_BUILTINS_FLOAT
mp_obj_t mp_obj_new_int_from_float(mp_float_t val);
@@ -659,6 +669,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed);
mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items);
mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items);
+mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable);
mp_obj_t mp_obj_new_dict(size_t n_args);
mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items);
mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
@@ -670,7 +681,7 @@ 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 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_instance_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);
@@ -719,7 +730,7 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values);
mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in);
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
-mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
+mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
void mp_init_emergency_exception_buf(void);
@@ -754,6 +765,7 @@ void mp_obj_tuple_del(mp_obj_t self_in);
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
// list
+mp_obj_t mp_obj_list_clear(mp_obj_t self_in);
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value);
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);
@@ -810,6 +822,10 @@ mp_obj_t mp_identity(mp_obj_t self);
MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj);
mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf);
+// Generic iterator that uses unary op and subscr to iterate over a native type. It will be slower
+// than a custom iterator but applies broadly.
+mp_obj_t mp_obj_new_generic_iterator(mp_obj_t self, mp_obj_iter_buf_t *iter_buf);
+
// module
typedef struct _mp_obj_module_t {
mp_obj_base_t base;
@@ -842,7 +858,10 @@ typedef struct {
mp_uint_t stop;
mp_int_t step;
} mp_bound_slice_t;
+void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result);
+// Compute the new length of a sequence and ensure an exception is thrown on overflow.
+size_t mp_seq_multiply_len(size_t item_sz, size_t len);
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);
diff --git a/py/objarray.c b/py/objarray.c
index 69ff6f328..fccb966a2 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -63,6 +63,10 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_bu
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
+#if MICROPY_CPYTHON_COMPAT
+STATIC mp_obj_t array_decode(size_t n_args, const mp_obj_t *args);
+#endif
+
/******************************************************************************/
// array
@@ -157,9 +161,9 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
#endif
#if MICROPY_PY_ARRAY
-STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 1, 2, false);
+ mp_arg_check_num(n_args, kw_args, 1, 2, false);
// get typecode
const char *typecode = mp_obj_str_get_str(args[0]);
@@ -175,9 +179,9 @@ STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY
-STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
if (n_args == 0) {
// no args: construct an empty bytearray
@@ -207,13 +211,13 @@ mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
return MP_OBJ_FROM_PTR(self);
}
-STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
// TODO possibly allow memoryview constructor to take start/stop so that one
// can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_arg_check_num(n_args, kw_args, 1, 1, false);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
@@ -546,7 +550,24 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui
return 0;
}
-#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
+
+#if MICROPY_CPYTHON_COMPAT && MICROPY_PY_BUILTINS_BYTEARRAY
+// Directly lifted from objstr.c
+STATIC mp_obj_t array_decode(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t new_args[2];
+ if (n_args == 1) {
+ new_args[0] = args[0];
+ new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8);
+ args = new_args;
+ n_args++;
+ }
+ return mp_obj_str_make_new(&mp_type_str, n_args, args, NULL);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(array_decode_obj, 1, 3, array_decode);
+#endif
+
+
+#if MICROPY_PY_ARRAY
STATIC const mp_rom_map_elem_t array_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) },
{ MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) },
@@ -555,6 +576,19 @@ STATIC const mp_rom_map_elem_t array_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
#endif
+#if MICROPY_PY_BUILTINS_BYTEARRAY
+STATIC const mp_rom_map_elem_t bytearray_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) },
+ { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) },
+#if MICROPY_CPYTHON_COMPAT
+ { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&array_decode_obj) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(bytearray_locals_dict, bytearray_locals_dict_table);
+#endif
+
+
#if MICROPY_PY_ARRAY
const mp_obj_type_t mp_type_array = {
{ &mp_type_type },
@@ -581,7 +615,7 @@ 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*)&bytearray_locals_dict,
};
#endif
@@ -611,6 +645,12 @@ mp_obj_t mp_obj_new_bytearray(size_t n, void *items) {
return MP_OBJ_FROM_PTR(o);
}
+mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n) {
+ mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
+ memset(o->items, 0, n);
+ return MP_OBJ_FROM_PTR(o);
+}
+
// Create bytearray which references specified memory area
mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) {
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
diff --git a/py/objbool.c b/py/objbool.c
index 5755b188e..cd7d7100c 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -50,9 +50,9 @@ STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
}
}
-STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
if (n_args == 0) {
return mp_const_false;
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 3336d7b05..b38e2c5fa 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -75,9 +75,9 @@ STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_
}
}
-STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 2, false);
+ mp_arg_check_num(n_args, kw_args, 0, 2, false);
switch (n_args) {
case 0:
diff --git a/py/objdeque.c b/py/objdeque.c
index dd0141831..b2785b5b6 100644
--- a/py/objdeque.c
+++ b/py/objdeque.c
@@ -44,8 +44,8 @@ typedef struct _mp_obj_deque_t {
#define FLAG_CHECK_OVERFLOW 1
} mp_obj_deque_t;
-STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 2, 3, false);
+STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 2, 3, false);
/* Initialization from existing sequence is not supported, so an empty
tuple must be passed as such. */
diff --git a/py/objdict.c b/py/objdict.c
index cd110f1c1..3ec3cbe80 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -31,6 +31,7 @@
#include "py/builtin.h"
#include "py/objtype.h"
+#include "supervisor/linker.h"
#include "supervisor/shared/translate.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)
@@ -81,7 +82,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) {
+STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_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;
@@ -90,11 +91,12 @@ STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
dict->map.is_ordered = 1;
}
#endif
- if (n_args > 0 || n_kw > 0) {
- mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg
- mp_map_t kwargs;
- mp_map_init_fixed_table(&kwargs, n_kw, args + n_args);
- dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2
+ if (n_args > 0 || kw_args != NULL) {
+ mp_obj_t args2[2] = {dict_out, NULL}; // args[0] is always valid, even if it's not a positional arg
+ if (n_args > 0) {
+ args2[1] = args[0];
+ }
+ dict_update(n_args + 1, args2, kw_args); // dict_update will check that n_args + 1 == 1 or 2
}
return dict_out;
}
@@ -323,12 +325,12 @@ 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) {
+STATIC mp_obj_t PLACE_IN_ITCM(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_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
mp_ensure_not_fixed(self);
- mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
+ mp_arg_check_num(n_args, kwargs, 1, 2, true);
if (n_args == 2) {
// given a positional argument
@@ -589,7 +591,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
return self->map.used;
}
-mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
+mp_obj_t PLACE_IN_ITCM(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_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_ensure_not_fixed(self);
diff --git a/py/objenumerate.c b/py/objenumerate.c
index 1a9d30f83..818725d85 100644
--- a/py/objenumerate.c
+++ b/py/objenumerate.c
@@ -39,7 +39,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) {
+STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
#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} },
@@ -50,7 +50,7 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz
struct {
mp_arg_val_t iterable, start;
} arg_vals;
- mp_arg_parse_all_kw_array(n_args, n_kw, args,
+ mp_arg_parse_all(n_args, args, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals);
// create enumerate object
@@ -59,7 +59,7 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz
o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL);
o->cur = arg_vals.start.u_int;
#else
- (void)n_kw;
+ (void)kw_args;
mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
o->base.type = type;
o->iter = mp_getiter(args[0], NULL);
diff --git a/py/objexcept.c b/py/objexcept.c
index c54e5fd4a..796be122f 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -112,17 +112,23 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
if (o->args == NULL || o->args->len == 0) {
mp_print_str(print, "");
return;
- } else if (o->args->len == 1) {
+ }
+ if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) &&
+ mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError)) &&
+ o->args->len <= 2) {
// try to provide a nice OSError error message
- if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) &&
- mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
- char decompressed[50];
- const char *msg = mp_common_errno_to_str(o->args->items[0], decompressed, sizeof(decompressed));
- if (msg != NULL) {
- mp_printf(print, "[Errno " INT_FMT "] %s", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), msg);
- return;
+ char decompressed[50];
+ const char *msg = mp_common_errno_to_str(o->args->items[0], decompressed, sizeof(decompressed));
+ if (msg != NULL) {
+ mp_printf(print, "[Errno " INT_FMT "] %s", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), msg);
+ // if second arg exists, it is filename.
+ if (o->args->len == 2) {
+ mp_printf(print, ": '%s'", mp_obj_str_get_str(o->args->items[1]));
}
+ return;
}
+ }
+ if (o->args->len == 1) {
mp_obj_print_helper(print, o->args->items[0], PRINT_STR);
return;
}
@@ -130,8 +136,8 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
mp_obj_tuple_print(print, MP_OBJ_FROM_PTR(o->args), kind);
}
-mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false);
+mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 0, MP_OBJ_FUN_ARGS_MAX, false);
// Try to allocate memory for the exception, with fallback to emergency exception object
mp_obj_exception_t *o_exc = m_new_obj_maybe(mp_obj_exception_t);
@@ -311,6 +317,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(UnicodeError, ValueError)
//TODO: Implement more UnicodeError subclasses which take arguments
#endif
+ MP_DEFINE_EXCEPTION(MpyError, ValueError)
/*
MP_DEFINE_EXCEPTION(Warning, Exception)
MP_DEFINE_EXCEPTION(DeprecationWarning, Warning)
@@ -336,7 +343,7 @@ 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) {
assert(exc_type->make_new == mp_obj_exception_make_new);
- return exc_type->make_new(exc_type, n_args, 0, args);
+ return exc_type->make_new(exc_type, n_args, args, NULL);
}
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
@@ -393,7 +400,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com
// 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 = fmt->length + 1;
+ size_t o_str_alloc = decompress_length(fmt);
byte *o_str_buf = m_new_maybe(byte, o_str_alloc);
bool used_emg_buf = false;
@@ -426,7 +433,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com
// We have some memory to format the string
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};
- char fmt_decompressed[fmt->length];
+ char fmt_decompressed[decompress_length(fmt)];
decompress(fmt, fmt_decompressed);
mp_vprintf(&print, fmt_decompressed, ap);
exc_pr.buf[exc_pr.len] = '\0';
@@ -438,7 +445,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com
o_str->base.type = &mp_type_str;
o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
mp_obj_t arg = MP_OBJ_FROM_PTR(o_str);
- return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
+ return mp_obj_exception_make_new(exc_type, 1, &arg, NULL);
}
// return true if the given object is an exception type
@@ -607,7 +614,7 @@ STATIC mp_obj_t code_make_new(qstr file, qstr block) {
mp_obj_new_bytearray(0, NULL), // co_lnotab
};
- return namedtuple_make_new((const mp_obj_type_t*)&code_type_obj, 15, 0, elems);
+ return namedtuple_make_new((const mp_obj_type_t*)&code_type_obj, 15, elems, NULL);
}
STATIC const mp_obj_namedtuple_type_t frame_type_obj = {
@@ -650,7 +657,7 @@ STATIC mp_obj_t frame_make_new(mp_obj_t f_code, int f_lineno) {
mp_const_none, // f_trace
};
- return namedtuple_make_new((const mp_obj_type_t*)&frame_type_obj, 8, 0, elems);
+ return namedtuple_make_new((const mp_obj_type_t*)&frame_type_obj, 8, elems, NULL);
}
STATIC const mp_obj_namedtuple_type_t traceback_type_obj = {
@@ -687,7 +694,7 @@ STATIC mp_obj_t traceback_from_values(size_t *values, mp_obj_t tb_next) {
tb_next,
};
- return namedtuple_make_new((const mp_obj_type_t*)&traceback_type_obj, 4, 0, elems);
+ return namedtuple_make_new((const mp_obj_type_t*)&traceback_type_obj, 4, elems, NULL);
};
mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in) {
diff --git a/py/objfilter.c b/py/objfilter.c
index cb965d8c3..af95326e6 100644
--- a/py/objfilter.c
+++ b/py/objfilter.c
@@ -34,8 +34,8 @@ typedef struct _mp_obj_filter_t {
mp_obj_t iter;
} mp_obj_filter_t;
-STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 2, 2, false);
+STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 2, 2, false);
mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t);
o->base.type = type;
o->fun = args[0];
diff --git a/py/objfloat.c b/py/objfloat.c
index c3f47018c..f544ade05 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -133,9 +133,9 @@ STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
}
}
-STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
switch (n_args) {
case 0:
diff --git a/py/objfun.c b/py/objfun.c
index 8c51d92e0..c586a290a 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -34,6 +34,8 @@
#include "py/bc.h"
#include "py/stackctrl.h"
+#include "supervisor/linker.h"
+
#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
#else // don't print debugging info
@@ -52,7 +54,7 @@ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw,
(void)args;
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0));
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
- mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, 0, 0, false);
return self->fun._0();
}
@@ -66,7 +68,7 @@ const mp_obj_type_t mp_type_fun_builtin_0 = {
STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1));
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, 1, 1, false);
return self->fun._1(args[0]);
}
@@ -80,7 +82,7 @@ const mp_obj_type_t mp_type_fun_builtin_1 = {
STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2));
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
- mp_arg_check_num(n_args, n_kw, 2, 2, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, 2, 2, false);
return self->fun._2(args[0], args[1]);
}
@@ -94,7 +96,7 @@ const mp_obj_type_t mp_type_fun_builtin_2 = {
STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3));
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
- mp_arg_check_num(n_args, n_kw, 3, 3, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, 3, 3, false);
return self->fun._3(args[0], args[1], args[2]);
}
@@ -110,7 +112,7 @@ STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_k
mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in);
// check number of arguments
- mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
+ mp_arg_check_num_kw_array(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
if (self->is_kw) {
// function allows keywords
@@ -249,7 +251,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args
}
#endif
-STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t PLACE_IN_ITCM(fun_bc_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
MP_STACK_CHECK();
DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw);
@@ -436,7 +438,7 @@ typedef mp_uint_t (*viper_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint_t);
STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_obj_fun_viper_t *self = self_in;
- mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, self->n_args, self->n_args, false);
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
@@ -546,7 +548,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_obj_fun_asm_t *self = self_in;
- mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
+ mp_arg_check_num_kw_array(n_args, n_kw, self->n_args, self->n_args, false);
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
diff --git a/py/objint.c b/py/objint.c
index 2ac370d17..b78c9f25b 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -42,9 +42,9 @@
#endif
// This dispatcher function is expected to be independent of the implementation of long int
-STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 2, false);
+ mp_arg_check_num(n_args, kw_args, 0, 2, false);
switch (n_args) {
case 0:
@@ -300,6 +300,76 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
return b;
}
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+
+void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed)
+{
+ if (is_signed) {
+ // self must be < 2**(bits - 1)
+ mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT,
+ mp_obj_new_int(1),
+ mp_obj_new_int(nbytes * 8 - 1));
+
+ if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) {
+ // and >= -2**(bits - 1)
+ edge = mp_unary_op(MP_UNARY_OP_NEGATIVE, edge);
+ if (mp_binary_op(MP_BINARY_OP_MORE_EQUAL, self_in, edge) == mp_const_true) {
+ return;
+ }
+ }
+ } else {
+ // self must be >= 0
+ if (mp_obj_int_sign(self_in) >= 0) {
+ // and < 2**(bits)
+ mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT,
+ mp_obj_new_int(1),
+ mp_obj_new_int(nbytes * 8));
+
+ if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) {
+ return;
+ }
+ }
+ }
+
+ mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes);
+}
+
+#endif // MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+
+void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed) {
+ // Fast path for zero.
+ if (val == 0) {
+ return;
+ }
+
+ // Trying to store negative values in unsigned bytes falls through to failure.
+ if (is_signed || val >= 0) {
+
+ if (nbytes >= sizeof(val)) {
+ // All non-negative N bit signed integers fit in an unsigned N bit integer.
+ // This case prevents shifting too far below.
+ return;
+ }
+
+ if (is_signed) {
+ mp_int_t edge = ((mp_int_t)1 << (nbytes * 8 - 1));
+ if (-edge <= val && val < edge) {
+ return;
+ }
+ // Out of range, fall through to failure.
+ } else {
+ // Unsigned. We already know val >= 0.
+ mp_int_t edge = ((mp_int_t)1 << (nbytes * 8));
+ if (val < edge) {
+ return;
+ }
+ }
+ // Fall through to failure.
+ }
+
+ mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes);
+}
+
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
int mp_obj_int_sign(mp_obj_t self_in) {
@@ -420,15 +490,24 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj));
-STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
- // TODO: Support signed param (assumes signed=False)
- (void)n_args;
-
- mp_int_t len = mp_obj_get_int(args[1]);
+STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_length, ARG_byteorder, ARG_signed };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t len = args[ARG_length].u_int;
if (len < 0) {
mp_raise_ValueError(NULL);
}
- bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little);
+
+ mp_obj_t self = pos_args[0];
+ bool big_endian = args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_little);
+ bool signed_ = args[ARG_signed].u_bool;
vstr_t vstr;
vstr_init_len(&vstr, len);
@@ -436,19 +515,26 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
memset(data, 0, len);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
- if (!MP_OBJ_IS_SMALL_INT(args[0])) {
- mp_obj_int_to_bytes_impl(args[0], big_endian, len, data);
+ if (!MP_OBJ_IS_SMALL_INT(self)) {
+ mp_obj_int_buffer_overflow_check(self, len, signed_);
+ mp_obj_int_to_bytes_impl(self, big_endian, len, data);
} else
#endif
{
- mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]);
+ mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self);
+ // Small int checking is separate, to be fast.
+ mp_small_int_buffer_overflow_check(val, len, signed_);
size_t l = MIN((size_t)len, sizeof(val));
+ if (val < 0) {
+ // Sign extend negative numbers.
+ memset(data, -1, len);
+ }
mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val);
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 3, 4, int_to_bytes);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 3, int_to_bytes);
STATIC const mp_rom_map_elem_t int_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) },
diff --git a/py/objint.h b/py/objint.h
index 4b95acde9..e8c9bc3e0 100644
--- a/py/objint.h
+++ b/py/objint.h
@@ -53,6 +53,12 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
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);
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed);
+#endif
+
+void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed);
+
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);
diff --git a/py/objlist.c b/py/objlist.c
index d4f9b0222..608ea9f6c 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -68,9 +68,14 @@ STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) {
return list;
}
-STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable) {
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ return list_extend_from_iter(list, iterable);
+}
+
+STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
switch (n_args) {
case 0:
@@ -88,7 +93,7 @@ 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);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
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);
@@ -103,7 +108,7 @@ STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
- mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs);
+ mp_obj_list_t *o = mp_instance_cast_to_native_base(lhs, &mp_type_list);
switch (op) {
case MP_BINARY_OP_ADD: {
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
@@ -126,7 +131,8 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
if (n < 0) {
n = 0;
}
- mp_obj_list_t *s = list_new(o->len * n);
+ size_t new_len = mp_seq_multiply_len(o->len, n);
+ mp_obj_list_t *s = list_new(new_len);
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
return MP_OBJ_FROM_PTR(s);
}
@@ -153,11 +159,11 @@ 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) {
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
if (value == MP_OBJ_NULL) {
// delete
#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;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
mp_raise_NotImplementedError(NULL);
@@ -173,12 +179,11 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
return mp_const_none;
}
#endif
- mp_obj_t args[2] = {self_in, index};
+ mp_obj_t args[2] = {self, 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 (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
@@ -195,7 +200,6 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
} else {
#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;
mp_obj_get_array(value, &value_len, &value_items);
mp_bound_slice_t slice_out;
@@ -224,7 +228,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
return mp_const_none;
}
#endif
- mp_obj_list_store(self_in, index, value);
+ mp_obj_list_store(self, index, value);
return mp_const_none;
}
}
@@ -235,7 +239,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
if (self->len >= self->alloc) {
self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2);
self->alloc *= 2;
@@ -248,8 +252,8 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
+ mp_obj_list_t *arg = mp_instance_cast_to_native_base(arg_in, &mp_type_list);
if (self->len + arg->len > self->alloc) {
// TODO: use alloc policy for "4"
@@ -268,7 +272,7 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) {
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]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list);
if (self->len == 0) {
mp_raise_IndexError(translate("pop from empty list"));
}
@@ -328,7 +332,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
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]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(pos_args[0], &mp_type_list);
if (self->len > 1) {
mp_quicksort(self->items, self->items + self->len - 1,
@@ -339,9 +343,9 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
return mp_const_none;
}
-STATIC mp_obj_t list_clear(mp_obj_t self_in) {
+mp_obj_t mp_obj_list_clear(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
self->len = 0;
self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC);
self->alloc = LIST_MIN_ALLOC;
@@ -351,25 +355,25 @@ STATIC mp_obj_t list_clear(mp_obj_t self_in) {
STATIC mp_obj_t list_copy(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
return mp_obj_new_list(self->len, self->items);
}
STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
return mp_seq_count_obj(self->items, self->len, value);
}
STATIC mp_obj_t list_index(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]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list);
return mp_seq_index_obj(self->items, self->len, n_args, args);
}
STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
// insert has its own strange index logic
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx);
if (index < 0) {
@@ -403,7 +407,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) {
STATIC mp_obj_t list_reverse(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
mp_int_t len = self->len;
for (mp_int_t i = 0; i < len/2; i++) {
@@ -417,7 +421,7 @@ STATIC mp_obj_t list_reverse(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, mp_obj_list_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index);
@@ -480,7 +484,7 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) {
}
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
*len = self->len;
*items = self->items;
}
@@ -493,7 +497,7 @@ void mp_obj_list_set_len(mp_obj_t self_in, size_t len) {
}
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
size_t i = mp_get_index(self->base.type, self->len, index, false);
self->items[i] = value;
}
diff --git a/py/objmap.c b/py/objmap.c
index 908c61507..cf71f99ee 100644
--- a/py/objmap.c
+++ b/py/objmap.c
@@ -36,8 +36,8 @@ typedef struct _mp_obj_map_t {
mp_obj_t iters[];
} mp_obj_map_t;
-STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 2, MP_OBJ_FUN_ARGS_MAX, false);
+STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 2, MP_OBJ_FUN_ARGS_MAX, false);
mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1);
o->base.type = type;
o->n_iters = n_args - 1;
diff --git a/py/objmodule.c b/py/objmodule.c
index 828f556f3..b6a8a084e 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -32,6 +32,8 @@
#include "py/runtime.h"
#include "py/builtin.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;
mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
@@ -67,6 +69,13 @@ STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// delete/store attribute
mp_obj_dict_t *dict = self->globals;
if (dict->map.is_fixed) {
+ mp_map_elem_t *elem = mp_map_lookup(&dict->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
+ // Return success if the given value is already in the dictionary. This is the case for
+ // native packages with native submodules.
+ if (elem != NULL && elem->value == dest[1]) {
+ dest[0] = MP_OBJ_NULL; // indicate success
+ return;
+ } else
#if MICROPY_CAN_OVERRIDE_BUILTINS
if (dict == &mp_module_builtins_globals) {
if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
@@ -148,11 +157,16 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
{ MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) },
#endif
#if MICROPY_PY_IO
+#if CIRCUITPY
+ { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io) },
+#else
{ MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },
#endif
+#endif
#if MICROPY_PY_COLLECTIONS
{ MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) },
#endif
+// CircuitPython: Now in shared-bindings/, so not defined here.
#if MICROPY_PY_STRUCT
{ MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) },
#endif
@@ -178,8 +192,13 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
// extmod modules
#if MICROPY_PY_UERRNO
+#if CIRCUITPY
+// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
+// TODO: move to shared-bindings/
+#else
{ MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) },
#endif
+#endif
#if MICROPY_PY_UCTYPES
{ MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },
#endif
@@ -187,11 +206,29 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
{ MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) },
#endif
#if MICROPY_PY_UJSON
+#if CIRCUITPY
+// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
+// TODO: move to shared-bindings/
+#else
{ MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) },
#endif
+#endif
+#if CIRCUITPY_ULAB
+#if CIRCUITPY
+// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
+// TODO: move to shared-bindings/
+#else
+ { MP_ROM_QSTR(MP_QSTR_ulab), MP_ROM_PTR(&ulab_user_cmodule) },
+#endif
+#endif
#if MICROPY_PY_URE
+#if CIRCUITPY
+// CircuitPython: Defined in MICROPY_PORT_BUILTIN_MODULES, so not defined here.
+// TODO: move to shared-bindings/
+#else
{ MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) },
#endif
+#endif
#if MICROPY_PY_UHEAPQ
{ MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) },
#endif
@@ -232,6 +269,11 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
+ #ifdef MICROPY_REGISTERED_MODULES
+ // builtin modules declared with MP_REGISTER_MODULE()
+ MICROPY_REGISTERED_MODULES
+ #endif
+
#if defined(MICROPY_DEBUG_MODULES) && defined(MICROPY_PORT_BUILTIN_DEBUG_MODULES)
, MICROPY_PORT_BUILTIN_DEBUG_MODULES
#endif
diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c
index 800991c43..84dcf7909 100644
--- a/py/objnamedtuple.c
+++ b/py/objnamedtuple.c
@@ -31,6 +31,7 @@
#include "py/runtime.h"
#include "py/objstr.h"
#include "py/objnamedtuple.h"
+#include "py/objtype.h"
#include "supervisor/shared/translate.h"
@@ -93,9 +94,13 @@ void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
}
-mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in;
size_t num_fields = type->n_fields;
+ size_t n_kw = 0;
+ if (kw_args != NULL) {
+ n_kw = kw_args->used;
+ }
if (n_args + n_kw != num_fields) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_arg_error_terse_mismatch();
@@ -119,8 +124,8 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t
// Fill in the remaining slots with the keyword args
memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw);
- for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) {
- qstr kw = mp_obj_str_get_qstr(args[i]);
+ for (size_t i = 0; i < n_kw; i++) {
+ qstr kw = mp_obj_str_get_qstr(kw_args->table[i].key);
size_t id = mp_obj_namedtuple_find_field(type, kw);
if (id == (size_t)-1) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
@@ -138,7 +143,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t
translate("function got multiple values for argument '%q'"), kw);
}
}
- tuple->items[id] = args[i + 1];
+ tuple->items[id] = kw_args->table[i].value;
}
return MP_OBJ_FROM_PTR(tuple);
diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h
index deac7107b..0ea0d2862 100644
--- a/py/objnamedtuple.h
+++ b/py/objnamedtuple.h
@@ -51,7 +51,7 @@ void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t ki
size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name);
void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields);
-mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
+mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
#endif // MICROPY_PY_COLLECTIONS
diff --git a/py/objobject.c b/py/objobject.c
index fa8c29cff..a42edde3c 100644
--- a/py/objobject.c
+++ b/py/objobject.c
@@ -35,9 +35,9 @@ typedef struct _mp_obj_object_t {
mp_obj_base_t base;
} mp_obj_object_t;
-STATIC mp_obj_t object_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t object_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)args;
- mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ mp_arg_check_num(n_args, kw_args, 0, 0, false);
mp_obj_object_t *o = m_new_obj(mp_obj_object_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
diff --git a/py/objproperty.c b/py/objproperty.c
index 4aba6c7a1..ddf484af2 100644
--- a/py/objproperty.c
+++ b/py/objproperty.c
@@ -33,7 +33,7 @@
#if MICROPY_PY_BUILTINS_PROPERTY
-STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
enum { ARG_fget, ARG_fset, ARG_fdel, ARG_doc };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
@@ -42,7 +42,7 @@ STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, size
{ MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
+ mp_arg_parse_all(n_args, args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
mp_obj_property_t *o = m_new_obj(mp_obj_property_t);
o->base.type = type;
diff --git a/py/objrange.c b/py/objrange.c
index 33c0d9b11..30d55c56c 100644
--- a/py/objrange.c
+++ b/py/objrange.c
@@ -91,8 +91,8 @@ STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind
}
}
-STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 3, false);
+STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 1, 3, false);
mp_obj_range_t *o = m_new_obj(mp_obj_range_t);
o->base.type = type;
diff --git a/py/objreversed.c b/py/objreversed.c
index e498b553d..4937d0818 100644
--- a/py/objreversed.c
+++ b/py/objreversed.c
@@ -37,8 +37,8 @@ typedef struct _mp_obj_reversed_t {
mp_uint_t cur_index; // current index, plus 1; 0=no more, 1=last one (index 0)
} mp_obj_reversed_t;
-STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 1, 1, false);
// check if __reversed__ exists, and if so delegate to it
mp_obj_t dest[2];
diff --git a/py/objset.c b/py/objset.c
index 00d6eae0e..5d1608c7e 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -103,8 +103,8 @@ STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
#endif
}
-STATIC mp_obj_t set_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+STATIC mp_obj_t set_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
switch (n_args) {
case 0: {
@@ -299,7 +299,7 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool
if (is_set_or_frozenset(self_in)) {
self = MP_OBJ_TO_PTR(self_in);
} else {
- self = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &self_in));
+ self = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, &self_in, NULL));
cleanup_self = true;
}
@@ -308,7 +308,7 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool
if (is_set_or_frozenset(other_in)) {
other = MP_OBJ_TO_PTR(other_in);
} else {
- other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &other_in));
+ other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, &other_in, NULL));
cleanup_other = true;
}
mp_obj_t out = mp_const_true;
diff --git a/py/objslice.c b/py/objslice.c
index 08f18935b..cbbee326e 100644
--- a/py/objslice.c
+++ b/py/objslice.c
@@ -130,7 +130,7 @@ STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
STATIC mp_obj_t slice_make_new(const mp_obj_type_t *type,
- size_t n_args, size_t n_kw, const mp_obj_t *args);
+ size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
#endif
const mp_obj_type_t mp_type_slice = {
@@ -152,14 +152,79 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
return MP_OBJ_FROM_PTR(o);
}
+// Return the real index and step values for a slice when applied to a sequence of
+// the given length, resolving missing components, negative values and values off
+// the end of the sequence.
+void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) {
+ mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t start, stop, step;
+
+ if (self->step == mp_const_none) {
+ step = 1;
+ } else {
+ step = mp_obj_get_int(self->step);
+ if (step == 0) {
+ mp_raise_ValueError(translate("slice step cannot be zero"));
+ }
+ }
+
+ if (step > 0) {
+ // Positive step
+ if (self->start == mp_const_none) {
+ start = 0;
+ } else {
+ start = mp_obj_get_int(self->start);
+ if (start < 0) {
+ start += length;
+ }
+ start = MIN(length, MAX(start, 0));
+ }
+
+ if (self->stop == mp_const_none) {
+ stop = length;
+ } else {
+ stop = mp_obj_get_int(self->stop);
+ if (stop < 0) {
+ stop += length;
+ }
+ stop = MIN(length, MAX(stop, 0));
+ }
+ } else {
+ // Negative step
+ if (self->start == mp_const_none) {
+ start = length - 1;
+ } else {
+ start = mp_obj_get_int(self->start);
+ if (start < 0) {
+ start += length;
+ }
+ start = MIN(length - 1, MAX(start, -1));
+ }
+
+ if (self->stop == mp_const_none) {
+ stop = -1;
+ } else {
+ stop = mp_obj_get_int(self->stop);
+ if (stop < 0) {
+ stop += length;
+ }
+ stop = MIN(length - 1, MAX(stop, -1));
+ }
+ }
+
+ result->start = start;
+ result->stop = stop;
+ result->step = step;
+}
+
#if MICROPY_PY_BUILTINS_SLICE_ATTRS
STATIC mp_obj_t slice_make_new(const mp_obj_type_t *type,
- size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
if (type != &mp_type_slice) {
mp_raise_NotImplementedError(translate("Cannot subclass slice"));
}
// check number of arguments
- mp_arg_check_num(n_args, n_kw, 1, 3, false);
+ mp_arg_check_num(n_args, kw_args, 1, 3, false);
// 1st argument is the pin
mp_obj_t start = mp_const_none;
diff --git a/py/objstr.c b/py/objstr.c
index 621f1b837..a60f507e9 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -31,6 +31,7 @@
#include "py/unicode.h"
#include "py/objstr.h"
#include "py/objlist.h"
+#include "py/objtype.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
@@ -41,6 +42,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
+const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'};
+
+const char nibble_to_hex_lower[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+
/******************************************************************************/
/* str */
@@ -132,14 +139,14 @@ STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
}
}
-mp_obj_t mp_obj_str_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_str_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
#if MICROPY_CPYTHON_COMPAT
- if (n_kw != 0) {
+ if (kw_args != NULL && kw_args->used != 0) {
mp_arg_error_unimpl_kw();
}
#endif
- mp_arg_check_num(n_args, n_kw, 0, 3, false);
+ mp_arg_check_num(n_args, kw_args, 0, 3, false);
switch (n_args) {
case 0:
@@ -190,15 +197,15 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
}
}
-STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
#if MICROPY_CPYTHON_COMPAT
- if (n_kw != 0) {
+ if (kw_args != NULL && kw_args->used != 0) {
mp_arg_error_unimpl_kw();
}
#else
- (void)n_kw;
+ (void)kw_args;
#endif
if (n_args == 0) {
@@ -220,10 +227,6 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
return MP_OBJ_FROM_PTR(o);
}
- if (n_args > 1) {
- goto wrong_args;
- }
-
if (MP_OBJ_IS_SMALL_INT(args[0])) {
mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);
if (len < 0) {
@@ -235,6 +238,17 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
+ if (n_args > 1) {
+ goto wrong_args;
+ }
+
+ // check if __bytes__ exists, and if so delegate to it
+ mp_obj_t dest[2];
+ mp_load_method_maybe(args[0], MP_QSTR___bytes__, dest);
+ if (dest[0] != MP_OBJ_NULL) {
+ return mp_call_method_n_kw(0, 0, dest);
+ }
+
// check if argument has the buffer protocol
mp_buffer_info_t bufinfo;
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
@@ -332,8 +346,9 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
return mp_const_empty_bytes;
}
}
+ size_t new_len = mp_seq_multiply_len(lhs_len, n);
vstr_t vstr;
- vstr_init_len(&vstr, lhs_len * n);
+ vstr_init_len(&vstr, new_len);
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf);
return mp_obj_new_str_from_vstr(lhs_type, &vstr);
}
@@ -407,6 +422,15 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// objstrunicode defines own version
+size_t str_offset_to_index(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
+ size_t offset) {
+ if (offset > self_len) {
+ mp_raise_ValueError(translate("offset out of bounds"));
+ }
+
+ return offset;
+}
+
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
mp_obj_t index, bool is_slice) {
size_t index_val = mp_get_index(type, self_len, index, is_slice);
@@ -455,7 +479,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) {
// arg is not a list nor a tuple, try to convert it to a list
// TODO: Try to optimize?
- arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg);
+ arg = mp_type_list.make_new(&mp_type_list, 1, &arg, NULL);
}
mp_obj_get_array(arg, &seq_len, &seq_items);
@@ -1328,7 +1352,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
terse_str_format_value_error();
} else {
mp_raise_ValueError_varg(
- translate("unknown format code '%c' for object of type 'float'"),
+ translate("unknown format code '%c' for object of type '%s'"),
type, mp_obj_get_type_str(arg));
}
}
@@ -1364,7 +1388,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
terse_str_format_value_error();
} else {
mp_raise_ValueError_varg(
- translate("unknown format code '%c' for object of type 'str'"),
+ translate("unknown format code '%c' for object of type '%s'"),
type, mp_obj_get_type_str(arg));
}
}
@@ -1875,7 +1899,7 @@ STATIC mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) {
args = new_args;
n_args++;
}
- return mp_obj_str_make_new(&mp_type_str, n_args, 0, args);
+ return mp_obj_str_make_new(&mp_type_str, n_args, args, NULL);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
@@ -1888,7 +1912,7 @@ STATIC mp_obj_t str_encode(size_t n_args, const mp_obj_t *args) {
args = new_args;
n_args++;
}
- return bytes_make_new(NULL, n_args, 0, args);
+ return bytes_make_new(NULL, n_args, args, NULL);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
#endif
@@ -2078,6 +2102,14 @@ mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) {
return mp_obj_new_str_copy(&mp_type_bytes, data, len);
}
+mp_obj_t mp_obj_new_bytes_of_zeros(size_t len) {
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+ memset(vstr.buf, 0, len);
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+
+
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) {
return s1 == s2;
diff --git a/py/objstr.h b/py/objstr.h
index 4e55cad09..61a11d0bd 100644
--- a/py/objstr.h
+++ b/py/objstr.h
@@ -61,7 +61,7 @@ const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len);
else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; str_data = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->data; }
#endif
-mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
+mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len);
mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args);
@@ -71,10 +71,15 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz
mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
+size_t str_offset_to_index(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
+ size_t offset);
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
mp_obj_t index, bool is_slice);
const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction);
+const char nibble_to_hex_upper[16];
+const char nibble_to_hex_lower[16];
+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj);
diff --git a/py/objstringio.c b/py/objstringio.c
index d21248ad7..178e6446c 100644
--- a/py/objstringio.c
+++ b/py/objstringio.c
@@ -186,8 +186,8 @@ STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) {
return o;
}
-STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- (void)n_kw; // TODO check n_kw==0
+STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ (void)kw_args; // TODO check kw_args->used == 0
mp_uint_t sz = 16;
bool initdata = false;
@@ -240,6 +240,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
STATIC const mp_stream_p_t stringio_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = stringio_read,
.write = stringio_write,
.ioctl = stringio_ioctl,
@@ -247,6 +248,7 @@ STATIC const mp_stream_p_t stringio_stream_p = {
};
STATIC const mp_stream_p_t bytesio_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = stringio_read,
.write = stringio_write,
.ioctl = stringio_ioctl,
diff --git a/py/objstrunicode.c b/py/objstrunicode.c
index 03106f987..30000a51e 100644
--- a/py/objstrunicode.c
+++ b/py/objstrunicode.c
@@ -112,6 +112,26 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
+size_t str_offset_to_index(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
+ size_t offset) {
+ if (offset > self_len) {
+ mp_raise_ValueError(translate("offset out of bounds"));
+ }
+
+ if (type == &mp_type_bytes) {
+ return offset;
+ }
+
+ size_t index_val = 0;
+ const byte *s = self_data;
+ for (size_t i = 0; i < offset; i++, s++) {
+ if (!UTF8_IS_CONT(*s)) {
+ ++index_val;
+ }
+ }
+ return index_val;
+}
+
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or
// be capped to the first/last character of the string, depending on is_slice.
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
diff --git a/py/objtuple.c b/py/objtuple.c
index b4f5b1bdf..0a2ed6f4c 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -29,6 +29,7 @@
#include "py/objtuple.h"
#include "py/runtime.h"
+#include "py/objtype.h"
#include "supervisor/shared/translate.h"
@@ -59,10 +60,10 @@ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
}
}
-STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_arg_check_num(n_args, kw_args, 0, 1, false);
switch (n_args) {
case 0:
@@ -160,7 +161,8 @@ mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
if (n <= 0) {
return mp_const_empty_tuple;
}
- mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL));
+ size_t new_len = mp_seq_multiply_len(o->len, n);
+ mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(new_len, NULL));
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
return MP_OBJ_FROM_PTR(s);
}
@@ -180,6 +182,11 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) {
// load
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);
+ // when called with a native type (eg namedtuple) using mp_obj_tuple_subscr, get the native self
+ if (self->base.type->subscr != &mp_obj_tuple_subscr) {
+ self = mp_instance_cast_to_native_base(self_in, &mp_type_tuple);
+ }
+
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
@@ -250,7 +257,8 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) {
}
void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) {
- assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple));
+ // type check is done on getiter method to allow tuple, namedtuple, attrtuple
+ mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter);
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);
*len = self->len;
*items = &self->items[0];
diff --git a/py/objtype.c b/py/objtype.c
index 95dfc2a15..ad68b85d2 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -34,6 +34,7 @@
#include "py/objtype.h"
#include "py/runtime.h"
+#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
#if MICROPY_DEBUG_VERBOSE // print debugging info
@@ -50,7 +51,7 @@
#define TYPE_FLAG_IS_SUBCLASSED (0x0001)
#define TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002)
-STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
+STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
/******************************************************************************/
// instance object
@@ -90,14 +91,14 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
// This wrapper function is allows a subclass of a native type to call the
// __init__() method (corresponding to type->make_new) of the native type.
-STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {
- mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);
+STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_obj_instance_t *self = MP_OBJ_TO_PTR(pos_args[0]);
const mp_obj_type_t *native_base = NULL;
instance_count_native_bases(self->base.type, &native_base);
- self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1);
+ self->subobj[0] = native_base->make_new(native_base, n_args - 1, pos_args + 1, kw_args);
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(native_base_init_wrapper_obj, 1, native_base_init_wrapper);
#if !MICROPY_CPYTHON_COMPAT
STATIC
@@ -117,6 +118,16 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_
return o;
}
+// When instances are first created they have the base_init wrapper as their native parent's
+// instance because make_new combines __new__ and __init__. This object is invalid for the native
+// code so it must call this method to ensure that the given object has been __init__'d and is
+// valid.
+void mp_obj_assert_native_inited(mp_obj_t native_object) {
+ if (native_object == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {
+ mp_raise_NotImplementedError(translate("Call super().__init__() before accessing native object."));
+ }
+}
+
// TODO
// This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO
// http://python-history.blogspot.com/2010/06/method-resolution-order.html
@@ -171,16 +182,12 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
// do a lookup, not a (base) type in which we found the class method.
const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj;
mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest);
+ } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_property)) {
+ lookup->dest[0] = elem->value;
+ return;
} else {
mp_obj_instance_t *obj = lookup->obj;
- mp_obj_t obj_obj;
- if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
- // If we're dealing with native base class, then it applies to native sub-object
- obj_obj = obj->subobj[0];
- } else {
- obj_obj = MP_OBJ_FROM_PTR(obj);
- }
- mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest);
+ mp_convert_member_lookup(MP_OBJ_FROM_PTR(obj), type, elem->value, lookup->dest);
}
#if DEBUG_PRINT
printf("mp_obj_class_lookup: Returning: ");
@@ -281,7 +288,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self);
}
-mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
assert(mp_obj_is_instance_type(self));
// look for __new__ function
@@ -297,6 +304,10 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
const mp_obj_type_t *native_base = NULL;
mp_obj_instance_t *o;
+ size_t n_kw = 0;
+ if (kw_args != 0) {
+ n_kw = kw_args->used;
+ }
if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) {
// Either there is no __new__() method defined or there is a native
// constructor. In both cases create a blank instance.
@@ -315,9 +326,14 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)};
new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2);
} else {
+ // TODO(tannewt): Could this be on the stack? It's deleted below.
mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
args2[0] = MP_OBJ_FROM_PTR(self);
- memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
+ memcpy(args2 + 1, args, n_args * sizeof(mp_obj_t));
+ if (kw_args) {
+ // copy in kwargs
+ memcpy(args2 + 1 + n_args, kw_args->table, 2 * n_kw * sizeof(mp_obj_t));
+ }
new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
}
@@ -343,13 +359,16 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
mp_obj_class_lookup(&lookup, self);
if (init_fn[0] != MP_OBJ_NULL) {
mp_obj_t init_ret;
- if (n_args == 0 && n_kw == 0) {
+ if (n_args == 0 && kw_args == NULL) {
init_ret = mp_call_method_n_kw(0, 0, init_fn);
} else {
+ // TODO(tannewt): Could this be on the stack? It's deleted below.
mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);
args2[0] = init_fn[0];
args2[1] = init_fn[1];
- memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
+ // copy in kwargs
+ memcpy(args2 + 2, args, n_args * sizeof(mp_obj_t));
+ memcpy(args2 + 2 + n_args, kw_args->table, 2 * n_kw * sizeof(mp_obj_t));
init_ret = mp_call_method_n_kw(n_args, n_kw, args2);
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
}
@@ -367,7 +386,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
// If the type had a native base that was not explicitly initialised
// (constructed) by the Python __init__() method then construct it now.
if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {
- o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args);
+ o->subobj[0] = native_base->make_new(native_base, n_args, args, kw_args);
}
return MP_OBJ_FROM_PTR(o);
@@ -826,8 +845,13 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 3;
}
- if (member[0] == MP_OBJ_SENTINEL) {
- return mp_obj_subscr(self->subobj[0], index, value);
+ if (member[0] == MP_OBJ_SENTINEL) { // native base subscr exists
+ mp_obj_type_t *subobj_type = mp_obj_get_type(self->subobj[0]);
+ // return mp_obj_subscr(self->subobj[0], index, value, instance);
+ mp_obj_t ret = subobj_type->subscr(self_in, index, value);
+ // May have called port specific C code. Make sure it didn't mess up the heap.
+ assert_heap_ok();
+ return ret;
} else if (member[0] != MP_OBJ_NULL) {
mp_obj_t args[3] = {self_in, index, value};
// TODO probably need to call mp_convert_member_lookup, and use mp_call_method_n_kw
@@ -951,6 +975,21 @@ STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
#endif
return false;
}
+
+STATIC bool map_has_special_accessors(const mp_map_t *map) {
+ if (map == NULL) {
+ return false;
+ }
+ for (size_t i = 0; i < map->alloc; i++) {
+ if (MP_MAP_SLOT_IS_FILLED(map, i)) {
+ const mp_map_elem_t *elem = &map->table[i];
+ if (check_for_special_accessors(elem->key, elem->value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
#endif
STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -959,10 +998,10 @@ STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
mp_printf(print, "<class '%q'>", self->name);
}
-STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
- mp_arg_check_num(n_args, n_kw, 1, 3, false);
+ mp_arg_check_num(n_args, kw_args, 1, 3, false);
switch (n_args) {
case 1:
@@ -992,8 +1031,10 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
}
}
- // make new instance
- mp_obj_t o = self->make_new(self, n_args, n_kw, args);
+ // create a map directly from the given args array and make a new instance
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ mp_obj_t o = self->make_new(self, n_args, args, &kw_args);
// return new instance
return o;
@@ -1053,7 +1094,7 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// store attribute
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
- elem->value = make_obj_long_lived(dest[1], 10);
+ elem->value = dest[1];
dest[0] = MP_OBJ_NULL; // indicate success
}
}
@@ -1143,20 +1184,6 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
o->locals_dict = make_dict_long_lived(locals_dict, 10);
- #if ENABLE_SPECIAL_ACCESSORS
- // Check if the class has any special accessor methods
- if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
- for (size_t i = 0; i < o->locals_dict->map.alloc; i++) {
- if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) {
- const mp_map_elem_t *elem = &o->locals_dict->map.table[i];
- if (check_for_special_accessors(elem->key, elem->value)) {
- o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
- break;
- }
- }
- }
- }
- #endif
const mp_obj_type_t *native_base;
size_t num_native_bases = instance_count_native_bases(o, &native_base);
@@ -1165,12 +1192,23 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
}
mp_map_t *locals_map = &o->locals_dict->map;
+ #if ENABLE_SPECIAL_ACCESSORS
+ // Check if the class has any special accessor methods
+ if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS) &&
+ (map_has_special_accessors(locals_map) ||
+ (num_native_bases == 1 &&
+ native_base->locals_dict != NULL &&
+ map_has_special_accessors(&native_base->locals_dict->map)))) {
+ o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
+ }
+ #endif
+
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
if (elem != NULL) {
// __new__ slot exists; check if it is a function
if (MP_OBJ_IS_FUN(elem->value)) {
// __new__ is a function, wrap it in a staticmethod decorator
- elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value);
+ elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, &elem->value, NULL);
}
}
@@ -1196,11 +1234,11 @@ STATIC void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind
mp_print_str(print, ">");
}
-STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)type_in;
// 0 arguments are turned into 2 in the compiler
// 1 argument is not yet implemented
- mp_arg_check_num(n_args, n_kw, 2, 2, false);
+ mp_arg_check_num(n_args, kw_args, 2, 2, false);
if(!MP_OBJ_IS_TYPE(args[0], &mp_type_type)) {
mp_raise_TypeError(translate("first argument to super() must be type"));
}
@@ -1394,11 +1432,14 @@ STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
-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_instance_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type) {
mp_obj_type_t *self_type = mp_obj_get_type(self_in);
if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) {
return MP_OBJ_NULL;
}
+ if (MP_OBJ_FROM_PTR(self_type) == native_type) {
+ return self_in;
+ }
mp_obj_instance_t *self = (mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in);
return self->subobj[0];
}
@@ -1406,10 +1447,10 @@ mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t
/******************************************************************************/
// staticmethod and classmethod types (probably should go in a different file)
-STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
assert(self == &mp_type_staticmethod || self == &mp_type_classmethod);
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_arg_check_num(n_args, kw_args, 1, 1, false);
mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t);
*o = (mp_obj_static_class_method_t){{self}, args[0]};
diff --git a/py/objtype.h b/py/objtype.h
index 3fc8c6e1b..a32c87496 100644
--- a/py/objtype.h
+++ b/py/objtype.h
@@ -37,6 +37,8 @@ typedef struct _mp_obj_instance_t {
// TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them
} mp_obj_instance_t;
+void mp_obj_assert_native_inited(mp_obj_t native_object);
+
#if MICROPY_CPYTHON_COMPAT
// this is needed for object.__new__
mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base);
@@ -49,6 +51,6 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
#define mp_obj_is_instance_type(type) ((type)->make_new == mp_obj_instance_make_new)
#define mp_obj_is_native_type(type) ((type)->make_new != mp_obj_instance_make_new)
// this needs to be exposed for the above macros to work correctly
-mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
+mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
#endif // MICROPY_INCLUDED_PY_OBJTYPE_H
diff --git a/py/objzip.c b/py/objzip.c
index 0183925e3..ce9afd55d 100644
--- a/py/objzip.c
+++ b/py/objzip.c
@@ -36,8 +36,8 @@ typedef struct _mp_obj_zip_t {
mp_obj_t iters[];
} mp_obj_zip_t;
-STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false);
+STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 0, MP_OBJ_FUN_ARGS_MAX, false);
mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args);
o->base.type = type;
diff --git a/py/parse.c b/py/parse.c
index 911b891e0..b8cfda2cb 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -477,6 +477,9 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) {
mp_parse_node_t pn;
mp_lexer_t *lex = parser->lexer;
if (lex->tok_kind == MP_TOKEN_NAME) {
+ if(lex->vstr.len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) {
+ mp_raise_msg(&mp_type_SyntaxError, translate("Name too long"));
+ }
qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len);
#if MICROPY_COMP_CONST
// if name is a standalone identifier, look it up in the table of dynamic constants
@@ -921,6 +924,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
backtrack = false;
}
for (; i < n; ++i) {
+ //printf("--> inside for @L924\n");
uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK;
if (kind == RULE_ARG_TOK) {
if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) {
@@ -1165,15 +1169,57 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
) {
syntax_error:;
mp_obj_t exc;
- if (lex->tok_kind == MP_TOKEN_INDENT) {
- exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
- translate("unexpected indent"));
- } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) {
- exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
- translate("unindent does not match any outer indentation level"));
- } else {
- exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
- translate("invalid syntax"));
+ switch(lex->tok_kind) {
+ case MP_TOKEN_INDENT:
+ exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
+ translate("unexpected indent"));
+ break;
+ case MP_TOKEN_DEDENT_MISMATCH:
+ exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
+ translate("unindent does not match any outer indentation level"));
+ break;
+#if MICROPY_COMP_FSTRING_LITERAL
+#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
+ case MP_TOKEN_FSTRING_BACKSLASH:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("f-string expression part cannot include a backslash"));
+ break;
+ case MP_TOKEN_FSTRING_COMMENT:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("f-string expression part cannot include a '#'"));
+ break;
+ case MP_TOKEN_FSTRING_UNCLOSED:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("f-string: expecting '}'"));
+ break;
+ case MP_TOKEN_FSTRING_UNOPENED:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("f-string: single '}' is not allowed"));
+ break;
+ case MP_TOKEN_FSTRING_EMPTY_EXP:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("f-string: empty expression not allowed"));
+ break;
+ case MP_TOKEN_FSTRING_RAW:
+ exc = mp_obj_new_exception_msg(&mp_type_NotImplementedError,
+ translate("raw f-strings are not implemented"));
+ break;
+#else
+ case MP_TOKEN_FSTRING_BACKSLASH:
+ case MP_TOKEN_FSTRING_COMMENT:
+ case MP_TOKEN_FSTRING_UNCLOSED:
+ case MP_TOKEN_FSTRING_UNOPENED:
+ case MP_TOKEN_FSTRING_EMPTY_EXP:
+ case MP_TOKEN_FSTRING_RAW:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("malformed f-string"));
+ break;
+#endif
+#endif
+ default:
+ exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
+ translate("invalid syntax"));
+ break;
}
// add traceback to give info about file name and location
// we don't have a 'block' name, so just pass the NULL qstr to indicate this
diff --git a/py/persistentcode.c b/py/persistentcode.c
index b44b5e38d..eb69bd407 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -102,20 +102,35 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_
#include "py/parsenum.h"
+STATIC void raise_corrupt_mpy(void) {
+ mp_raise_RuntimeError(translate("Corrupt .mpy file"));
+}
+
STATIC int read_byte(mp_reader_t *reader) {
- return reader->readbyte(reader->data);
+ mp_uint_t b = reader->readbyte(reader->data);
+ if (b == MP_READER_EOF) {
+ raise_corrupt_mpy();
+ }
+ return b;
}
STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) {
while (len-- > 0) {
- *buf++ = reader->readbyte(reader->data);
+ mp_uint_t b =reader->readbyte(reader->data);
+ if (b == MP_READER_EOF) {
+ raise_corrupt_mpy();
+ }
+ *buf++ = b;
}
}
STATIC size_t read_uint(mp_reader_t *reader) {
size_t unum = 0;
for (;;) {
- byte b = reader->readbyte(reader->data);
+ mp_uint_t b = reader->readbyte(reader->data);
+ if (b == MP_READER_EOF) {
+ raise_corrupt_mpy();
+ }
unum = (unum << 7) | (b & 0x7f);
if ((b & 0x80) == 0) {
break;
@@ -145,11 +160,12 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) {
return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr);
} else if (obj_type == 'i') {
return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
- } else {
- assert(obj_type == 'f' || obj_type == 'c');
+ } else if (obj_type == 'f' || obj_type == 'c') {
return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL);
}
}
+ raise_corrupt_mpy();
+ return MP_OBJ_FROM_PTR(&mp_const_none_obj);
}
STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) {
@@ -220,7 +236,7 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) {
|| header[1] != MPY_VERSION
|| header[2] != MPY_FEATURE_FLAGS
|| header[3] > mp_small_int_bits()) {
- mp_raise_ValueError(translate("Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info."));
+ mp_raise_MpyError(translate("Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info."));
}
mp_raw_code_t *rc = load_raw_code(reader);
reader->close(reader->data);
diff --git a/py/proto.c b/py/proto.c
new file mode 100644
index 000000000..e5053130b
--- /dev/null
+++ b/py/proto.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/proto.h"
+#include "py/runtime.h"
+
+#ifndef MICROPY_UNSAFE_PROTO
+const void *mp_proto_get(uint16_t name, mp_const_obj_t obj) {
+ mp_obj_type_t *type = mp_obj_get_type(obj);
+ if (!type->protocol) return NULL;
+ uint16_t proto_name = *(const uint16_t*) type->protocol;
+ if (proto_name == name) {
+ return type->protocol;
+ }
+ return NULL;
+}
+#endif
+
+const void *mp_proto_get_or_throw(uint16_t name, mp_const_obj_t obj) {
+ const void *proto = mp_proto_get(name, obj);
+ if (proto) {
+ return proto;
+ }
+ mp_raise_TypeError_varg(translate("'%s' object does not support '%q'"),
+ mp_obj_get_type_str(obj), name);
+}
diff --git a/py/proto.h b/py/proto.h
new file mode 100644
index 000000000..fadf1f882
--- /dev/null
+++ b/py/proto.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_PY_PROTO_H
+#define MICROPY_INCLUDED_PY_PROTO_H
+
+#ifdef MICROPY_UNSAFE_PROTO
+#define MP_PROTOCOL_HEAD /* NOTHING */
+#define MP_PROTO_IMPLEMENT(name) /* NOTHING */
+static inline void *mp_proto_get(uint16_t name, mp_const_obj_type_t obj) { return mp_obj_get_type(obj)->protocol; }
+#else
+#define MP_PROTOCOL_HEAD \
+ uint16_t name; // The name of this protocol, a qstr
+#define MP_PROTO_IMPLEMENT(n) .name = n,
+const void *mp_proto_get(uint16_t name, mp_const_obj_t obj);
+const void *mp_proto_get_or_throw(uint16_t name, mp_const_obj_t obj);
+#endif
+
+#endif
diff --git a/py/py.mk b/py/py.mk
index 69ad4e9b9..3cb505920 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -105,6 +105,30 @@ $(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare
$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS)
endif
+ifeq ($(CIRCUITPY_ULAB),1)
+SRC_MOD += $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/extmod/ulab/code/*.c))
+CFLAGS_MOD += -DCIRCUITPY_ULAB=1 -DMODULE_ULAB_ENABLED=1
+$(BUILD)/extmod/ulab/code/%.o: CFLAGS += -Wno-float-equal -Wno-sign-compare -DCIRCUITPY
+endif
+
+# External modules written in C.
+ifneq ($(USER_C_MODULES),)
+# pre-define USERMOD variables as expanded so that variables are immediate
+# expanded as they're added to them
+SRC_USERMOD :=
+CFLAGS_USERMOD :=
+LDFLAGS_USERMOD :=
+$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \
+ $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\
+ $(info Including User C Module from $(USERMOD_DIR))\
+ $(eval include $(module))\
+)
+
+SRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD))
+CFLAGS_MOD += $(CFLAGS_USERMOD)
+LDFLAGS_MOD += $(LDFLAGS_USERMOD)
+endif
+
# py object files
PY_CORE_O_BASENAME = $(addprefix py/,\
mpstate.o \
@@ -196,6 +220,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
objtype.o \
objzip.o \
opmethods.o \
+ proto.o \
reload.o \
sequence.o \
stream.o \
@@ -221,6 +246,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
repl.o \
smallint.o \
frozenmod.o \
+ ringbuf.o \
)
PY_EXTMOD_O_BASENAME = \
@@ -233,12 +259,6 @@ PY_EXTMOD_O_BASENAME = \
extmod/moduhashlib.o \
extmod/modubinascii.o \
extmod/virtpin.o \
- extmod/machine_mem.o \
- extmod/machine_pinbase.o \
- extmod/machine_signal.o \
- extmod/machine_pulse.o \
- extmod/machine_i2c.o \
- extmod/machine_spi.o \
extmod/modussl_axtls.o \
extmod/modussl_mbedtls.o \
extmod/modurandom.o \
@@ -291,13 +311,20 @@ FORCE:
$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
$(STEPECHO) "GEN $@"
- $(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $@
+ $(Q)$(PYTHON3) $(PY_SRC)/makeversionhdr.py $@
+
+# build a list of registered modules for py/objmodule.c.
+$(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h
+ @$(STEPECHO) "GEN $@"
+ $(Q)$(PYTHON3) $(PY_SRC)/makemoduledefs.py --vpath="., $(TOP), $(USER_C_MODULES)" $(SRC_QSTR) > $@
+
+SRC_QSTR += $(HEADER_BUILD)/moduledefs.h
# mpconfigport.mk is optional, but changes to it may drastically change
# overall config, so they need to be caught
MPCONFIGPORT_MK = $(wildcard mpconfigport.mk)
-$(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po
+$(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po | $(HEADER_BUILD)
$(Q)msgfmt -o $@ $^
$(HEADER_BUILD)/qstrdefs.preprocessed.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)
@@ -324,10 +351,23 @@ $(PY_BUILD)/qstr.o: $(HEADER_BUILD)/qstrdefs.generated.h
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
# optimising gc for speed; 5ms down to 4ms on pybv2
+ifndef SUPEROPT_GC
+ SUPEROPT_GC = 1
+endif
+
+ifeq ($(SUPEROPT_GC),1)
$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)
+endif
# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)
+ifndef SUPEROPT_VM
+ SUPEROPT_VM = 1
+endif
+
+ifeq ($(SUPEROPT_VM),1)
$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT)
+endif
+
# Optimizing vm.o for modern deeply pipelined CPUs with branch predictors
# may require disabling tail jump optimization. This will make sure that
# each opcode has its own dispatching jump which will improve branch
diff --git a/py/qstr.c b/py/qstr.c
index eea57c1e0..bb8024435 100755
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -33,6 +33,8 @@
#include "py/qstr.h"
#include "py/gc.h"
+#include "supervisor/linker.h"
+
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
// ultimately we will replace this with a static hash table of some kind
// also probably need to include the length in the string data, to allow null bytes in the string
@@ -248,7 +250,7 @@ qstr qstr_from_strn(const char *str, size_t len) {
return q;
}
-mp_uint_t qstr_hash(qstr q) {
+mp_uint_t PLACE_IN_ITCM(qstr_hash)(qstr q) {
return Q_GET_HASH(find_qstr(q));
}
diff --git a/py/repl.c b/py/repl.c
index da0fefb3a..aa91c3f12 100644
--- a/py/repl.c
+++ b/py/repl.c
@@ -187,6 +187,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
mp_load_method_protected(obj, q, dest, true);
if (dest[0] != MP_OBJ_NULL) {
+ // special case; filter out words that begin with underscore
+ // unless there's already a partial match
+ if (s_len == 0 && d_str[0] == '_') {
+ continue;
+ }
if (match_str == NULL) {
match_str = d_str;
match_len = d_len;
@@ -210,6 +215,10 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
// nothing found
if (q_first == 0) {
+ if (s_len == 0) {
+ *compl_str = " ";
+ return 4;
+ }
// If there're no better alternatives, and if it's first word
// in the line, try to complete "import".
if (s_start == org_str) {
diff --git a/py/ringbuf.c b/py/ringbuf.c
new file mode 100644
index 000000000..c19f1d44b
--- /dev/null
+++ b/py/ringbuf.c
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ringbuf.h"
+
+// Dynamic initialization. This should be accessible from a root pointer.
+// capacity is the number of bytes the ring buffer can hold. The actual
+// size of the buffer is one greater than that, due to how the buffer
+// handles empty and full statuses.
+bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived) {
+ r->buf = gc_alloc(capacity + 1, false, long_lived);
+ r->size = capacity + 1;
+ r->iget = r->iput = 0;
+ return r->buf != NULL;
+}
+
+void ringbuf_free(ringbuf_t *r) {
+ gc_free(r->buf);
+ r->size = 0;
+ ringbuf_clear(r);
+}
+
+size_t ringbuf_capacity(ringbuf_t *r) {
+ return r->size - 1;
+}
+
+// Returns -1 if buffer is empty, else returns byte fetched.
+int ringbuf_get(ringbuf_t *r) {
+ if (r->iget == r->iput) {
+ return -1;
+ }
+ uint8_t v = r->buf[r->iget++];
+ if (r->iget >= r->size) {
+ r->iget = 0;
+ }
+ return v;
+}
+
+// Returns -1 if no room in buffer, else returns 0.
+int ringbuf_put(ringbuf_t *r, uint8_t v) {
+ uint32_t iput_new = r->iput + 1;
+ if (iput_new >= r->size) {
+ iput_new = 0;
+ }
+ if (iput_new == r->iget) {
+ return -1;
+ }
+ r->buf[r->iput] = v;
+ r->iput = iput_new;
+ return 0;
+}
+
+void ringbuf_clear(ringbuf_t *r) {
+ r->iput = r->iget = 0;
+}
+
+// Number of free slots that can be written.
+size_t ringbuf_num_empty(ringbuf_t *r) {
+ return (r->size + r->iget - r->iput - 1) % r->size;
+}
+
+// Number of bytes available to read.
+size_t ringbuf_num_filled(ringbuf_t *r) {
+ return (r->size + r->iput - r->iget) % r->size;
+}
+
+// If the ring buffer fills up, not all bytes will be written.
+// Returns how many bytes were successfully written.
+size_t ringbuf_put_n(ringbuf_t* r, uint8_t* buf, size_t bufsize)
+{
+ for(size_t i=0; i < bufsize; i++) {
+ if ( ringbuf_put(r, buf[i]) < 0 ) {
+ // If ringbuf is full, give up and return how many bytes
+ // we wrote so far.
+ return i;
+ }
+ }
+ return bufsize;
+}
+
+// Returns how many bytes were fetched.
+size_t ringbuf_get_n(ringbuf_t* r, uint8_t* buf, size_t bufsize)
+{
+ for(size_t i=0; i < bufsize; i++) {
+ int b = ringbuf_get(r);
+ if (b < 0) {
+ return i;
+ }
+ buf[i] = b;
+ }
+ return bufsize;
+}
diff --git a/py/ringbuf.h b/py/ringbuf.h
index c62e20e1d..476bd428f 100644
--- a/py/ringbuf.h
+++ b/py/ringbuf.h
@@ -26,49 +26,33 @@
#ifndef MICROPY_INCLUDED_PY_RINGBUF_H
#define MICROPY_INCLUDED_PY_RINGBUF_H
+#include "py/gc.h"
+
#include <stdint.h>
typedef struct _ringbuf_t {
uint8_t *buf;
- uint16_t size;
- uint16_t iget;
- uint16_t iput;
+ // Allocated size; capacity is one less. Don't reference this directly.
+ uint32_t size;
+ uint32_t iget;
+ uint32_t iput;
} ringbuf_t;
+// Note that the capacity of the buffer is N-1!
+
// Static initialization:
// byte buf_array[N];
// ringbuf_t buf = {buf_array, sizeof(buf_array)};
-// Dynamic initialization. This creates root pointer!
-#define ringbuf_alloc(r, sz) \
-{ \
- (r)->buf = m_new(uint8_t, sz); \
- (r)->size = sz; \
- (r)->iget = (r)->iput = 0; \
-}
-
-static inline int ringbuf_get(ringbuf_t *r) {
- if (r->iget == r->iput) {
- return -1;
- }
- uint8_t v = r->buf[r->iget++];
- if (r->iget >= r->size) {
- r->iget = 0;
- }
- return v;
-}
-
-static inline int ringbuf_put(ringbuf_t *r, uint8_t v) {
- uint32_t iput_new = r->iput + 1;
- if (iput_new >= r->size) {
- iput_new = 0;
- }
- if (iput_new == r->iget) {
- return -1;
- }
- r->buf[r->iput] = v;
- r->iput = iput_new;
- return 0;
-}
+bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived);
+void ringbuf_free(ringbuf_t *r);
+size_t ringbuf_capacity(ringbuf_t *r);
+int ringbuf_get(ringbuf_t *r);
+int ringbuf_put(ringbuf_t *r, uint8_t v);
+void ringbuf_clear(ringbuf_t *r);
+size_t ringbuf_num_empty(ringbuf_t *r);
+size_t ringbuf_num_filled(ringbuf_t *r);
+size_t ringbuf_put_n(ringbuf_t* r, uint8_t* buf, size_t bufsize);
+size_t ringbuf_get_n(ringbuf_t* r, uint8_t* buf, size_t bufsize);
#endif // MICROPY_INCLUDED_PY_RINGBUF_H
diff --git a/py/runtime.c b/py/runtime.c
index 3d7a97f58..59dcbc7a1 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -29,12 +29,12 @@
#include <string.h>
#include <assert.h>
+
#include "extmod/vfs.h"
-// #include "py/mpstate.h"
-// #include "py/nlr.h"
#include "py/parsenum.h"
#include "py/compile.h"
+#include "py/mperrno.h"
#include "py/objstr.h"
#include "py/objtuple.h"
#include "py/objtype.h"
@@ -131,31 +131,6 @@ void mp_init(void) {
sizeof(MP_STATE_VM(fs_user_mount)) - MICROPY_FATFS_NUM_PERSISTENT);
#endif
- #if MICROPY_VFS
- #if MICROPY_FATFS_NUM_PERSISTENT > 0
- // We preserve the last MICROPY_FATFS_NUM_PERSISTENT mounts because newer
- // mounts are put at the front of the list.
- mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table);
- // Count how many mounts we have.
- uint8_t count = 0;
- while (vfs != NULL) {
- vfs = vfs->next;
- count++;
- }
- // Find the vfs MICROPY_FATFS_NUM_PERSISTENT mounts from the end.
- vfs = MP_STATE_VM(vfs_mount_table);
- for (uint8_t j = 0; j < count - MICROPY_FATFS_NUM_PERSISTENT; j++) {
- vfs = vfs->next;
- }
- MP_STATE_VM(vfs_mount_table) = vfs;
- MP_STATE_VM(vfs_cur) = vfs;
- #else
- // initialise the VFS sub-system
- MP_STATE_VM(vfs_cur) = NULL;
- MP_STATE_VM(vfs_mount_table) = NULL;
- #endif
- #endif
-
#if MICROPY_PY_THREAD_GIL
mp_thread_mutex_init(&MP_STATE_VM(gil_mutex));
#endif
@@ -227,7 +202,7 @@ mp_obj_t mp_load_build_class(void) {
return MP_OBJ_FROM_PTR(&mp_builtin___build_class___obj);
}
-void mp_store_name(qstr qst, mp_obj_t obj) {
+void PLACE_IN_ITCM(mp_store_name)(qstr qst, mp_obj_t obj) {
DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qst), obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj);
}
@@ -238,7 +213,7 @@ void mp_delete_name(qstr qst) {
mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst));
}
-void mp_store_global(qstr qst, mp_obj_t obj) {
+void PLACE_IN_ITCM(mp_store_global)(qstr qst, mp_obj_t obj) {
DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qst), obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj);
}
@@ -310,7 +285,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
}
}
-mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
+mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs);
// TODO correctly distinguish inplace operators for mutable objects
@@ -668,7 +643,7 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) {
#if !MICROPY_STACKLESS
STATIC
#endif
-void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) {
+void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) {
mp_obj_t fun = *args++;
mp_obj_t self = MP_OBJ_NULL;
if (have_self) {
@@ -1197,7 +1172,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
mp_raise_AttributeError(translate("no such attribute"));
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError,
- translate("'%s' object has no attribute '%q'"),
+ translate("'%s' object cannot assign attribute '%q'"),
mp_obj_get_type_str(base), attr));
}
}
@@ -1599,11 +1574,50 @@ NORETURN void mp_raise_OSError(int errno_) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)));
}
+NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg) {
+ mp_raise_msg(&mp_type_OSError, msg);
+}
+
+NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) {
+ mp_obj_t args[2] = {
+ MP_OBJ_NEW_SMALL_INT(errno_),
+ str,
+ };
+ nlr_raise(mp_obj_new_exception_args(&mp_type_OSError, 2, args));
+}
+
+NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_OSError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg) {
mp_raise_msg(&mp_type_NotImplementedError, msg);
}
+NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_NotImplementedError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_OverflowError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+NORETURN void mp_raise_MpyError(const compressed_string_t *msg) {
+ mp_raise_msg(&mp_type_MpyError, msg);
+}
+
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
NORETURN void mp_raise_recursion_depth(void) {
mp_raise_RuntimeError(translate("maximum recursion depth exceeded"));
diff --git a/py/runtime.h b/py/runtime.h
index 9c7ffc02f..f81103557 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -29,6 +29,8 @@
#include "py/mpstate.h"
#include "py/pystack.h"
+#include "supervisor/linker.h"
+
typedef enum {
MP_VM_RETURN_NORMAL,
MP_VM_RETURN_YIELD,
@@ -77,16 +79,17 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg);
// extra printing method specifically for mp_obj_t's which are integral type
int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec);
-void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw);
+void mp_arg_check_num(size_t n_args, mp_map_t *kw_args, size_t n_args_min, size_t n_args_max, bool takes_kw);
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_check_num_kw_array(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw);
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);
NORETURN void mp_arg_error_terse_mismatch(void);
NORETURN void mp_arg_error_unimpl_kw(void);
-static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); }
-static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; }
-static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_THREAD(dict_globals); }
-static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; }
+static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_locals_get)(void) { return MP_STATE_THREAD(dict_locals); }
+static inline void PLACE_IN_ITCM(mp_locals_set)(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; }
+static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_globals_get)(void) { return MP_STATE_THREAD(dict_globals); }
+static inline void PLACE_IN_ITCM(mp_globals_set)(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; }
mp_obj_t mp_load_name(qstr qst);
mp_obj_t mp_load_global(qstr qst);
@@ -158,7 +161,13 @@ NORETURN void mp_raise_RuntimeError(const compressed_string_t *msg);
NORETURN void mp_raise_ImportError(const compressed_string_t *msg);
NORETURN void mp_raise_IndexError(const compressed_string_t *msg);
NORETURN void mp_raise_OSError(int errno_);
+NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str);
+NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg);
+NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...);
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_MpyError(const compressed_string_t *msg);
NORETURN void mp_raise_recursion_depth(void);
#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
diff --git a/py/sequence.c b/py/sequence.c
index cc31be983..0e668ea2a 100644
--- a/py/sequence.c
+++ b/py/sequence.c
@@ -34,6 +34,20 @@
#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
+#if __GNUC__ < 5
+// n.b. does not actually detect overflow!
+#define __builtin_mul_overflow(a, b, x) (*(x) = (a) * (b), false)
+#endif
+
+// Detect when a multiply causes an overflow.
+size_t mp_seq_multiply_len(size_t item_sz, size_t len) {
+ size_t new_len;
+ if (__builtin_mul_overflow(item_sz, len, &new_len)) {
+ mp_raise_msg(&mp_type_OverflowError, translate("small int overflow"));
+ }
+ return new_len;
+}
+
// Implements backend of sequence * integer operation. Assumes elements are
// memory-adjacent in sequence.
void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) {
diff --git a/py/showbc.c b/py/showbc.c
index 3deb18cd3..e71d8a253 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -185,7 +185,7 @@ const byte *mp_bytecode_print_str(const byte *ip) {
num--;
}
do {
- num = (num << 7) | (*ip & 0x7f);
+ num = (num * 128) | (*ip & 0x7f);
} while ((*ip++ & 0x80) != 0);
printf("LOAD_CONST_SMALL_INT " INT_FMT, num);
break;
diff --git a/py/stackctrl.c b/py/stackctrl.c
index 46cbefc8c..26fc065b7 100644
--- a/py/stackctrl.c
+++ b/py/stackctrl.c
@@ -77,7 +77,7 @@ void mp_stack_set_bottom(void* stack_bottom) {
//
// The stack_dummy approach used elsewhere in this file is not safe in
// all cases. That value may be below the actual top of the stack.
-static void* approx_stack_pointer(void){
+static void* approx_stack_pointer(void){
__asm volatile ("");
return __builtin_frame_address(0);
}
@@ -90,7 +90,7 @@ void mp_stack_fill_with_sentinel(void) {
// Continue until we've hit the bottom of the stack (lowest address,
// logical "ceiling" of stack).
char* p = (char *) approx_stack_pointer() - 1;
-
+
while(p >= MP_STATE_THREAD(stack_bottom)) {
*p-- = MP_MAX_STACK_USAGE_SENTINEL_BYTE;
}
diff --git a/py/stream.c b/py/stream.c
index 8cf375b16..2ff2b76a6 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -86,8 +86,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode
}
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {
- mp_obj_type_t *type = mp_obj_get_type(self_in);
- const mp_stream_p_t *stream_p = type->protocol;
+ const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, self_in);
if (stream_p == NULL
|| ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL)
|| ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL)
@@ -103,7 +102,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl
// CPython does a readall, but here we silently let negatives through,
// and they will cause a MemoryError.
mp_int_t sz;
- if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) {
+ if (n_args == 1 || args[1] == mp_const_none || ((sz = mp_obj_get_int(args[1])) == -1)) {
return stream_readall(args[0]);
}
@@ -250,6 +249,9 @@ void mp_stream_write_adaptor(void *self, const char *buf, size_t len) {
STATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
+ if (!mp_get_stream(args[0])->is_text && MP_OBJ_IS_STR(args[1])) {
+ mp_raise_ValueError(translate("string not supported; use bytes or bytearray"));
+ }
size_t max_len = (size_t)-1;
size_t off = 0;
if (n_args == 3) {
@@ -282,6 +284,9 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
// https://docs.python.org/3/library/socket.html#socket.socket.recv_into
mp_uint_t len = bufinfo.len;
if (n_args > 2) {
+ if (mp_get_stream(args[0])->pyserial_compatibility) {
+ mp_raise_ValueError(translate("length argument not allowed for this type"));
+ }
len = mp_obj_get_int(args[2]);
if (len > bufinfo.len) {
len = bufinfo.len;
@@ -335,6 +340,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE);
current_read = DEFAULT_BUFFER_SIZE;
}
+ #ifdef RUN_BACKGROUND_TASKS
+ RUN_BACKGROUND_TASKS;
+ #endif
}
vstr.len = total_size;
@@ -462,16 +470,19 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) {
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell);
-STATIC mp_obj_t stream_flush(mp_obj_t self) {
+mp_obj_t mp_stream_flush(mp_obj_t self) {
const mp_stream_p_t *stream_p = mp_get_stream(self);
int error;
+ if (stream_p->ioctl == NULL) {
+ mp_raise_OSError(MP_EINVAL);
+ }
mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error);
if (res == MP_STREAM_ERROR) {
mp_raise_OSError(error);
}
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush);
+MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, mp_stream_flush);
STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
@@ -510,7 +521,7 @@ int mp_stream_errno;
ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->write(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -521,7 +532,7 @@ ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->read(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -532,7 +543,7 @@ ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
const mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
struct mp_stream_seek_t seek_s;
seek_s.offset = offset;
seek_s.whence = whence;
@@ -545,7 +556,7 @@ off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
int mp_stream_posix_fsync(mp_obj_t stream) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_FLUSH, 0, &mp_stream_errno);
if (res == MP_STREAM_ERROR) {
return -1;
diff --git a/py/stream.h b/py/stream.h
index 7b953138c..dc9fc84c9 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -27,6 +27,7 @@
#define MICROPY_INCLUDED_PY_STREAM_H
#include "py/obj.h"
+#include "py/proto.h"
#include "py/mperrno.h"
#define MP_STREAM_ERROR ((mp_uint_t)-1)
@@ -64,12 +65,14 @@ struct mp_stream_seek_t {
// Stream protocol
typedef struct _mp_stream_p_t {
+ MP_PROTOCOL_HEAD
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
// are implementation-dependent, but will be exposed to user, e.g. via exception).
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
mp_uint_t is_text : 1; // default is bytes, set this for text stream
+ bool pyserial_compatibility: 1; // adjust API to match pyserial more closely
} mp_stream_p_t;
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj);
@@ -92,7 +95,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj);
// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods
static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) {
- return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol;
+ return mp_proto_get(MP_QSTR_protocol_stream, self);
}
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags);
@@ -112,6 +115,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode,
#define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ)
void mp_stream_write_adaptor(void *self, const char *buf, size_t len);
+mp_obj_t mp_stream_flush(mp_obj_t self);
#if MICROPY_STREAMS_POSIX_API
// Functions with POSIX-compatible signatures
diff --git a/py/vm.c b/py/vm.c
index b5f53ee9a..4f0340681 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -35,6 +35,8 @@
#include "py/bc0.h"
#include "py/bc.h"
+#include "supervisor/linker.h"
+
#if 0
#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table);
#else
@@ -116,7 +118,7 @@
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
// MP_VM_RETURN_EXCEPTION, exception in fastn[0]
-mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
+mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
#define SELECTIVE_EXC_IP (0)
#if SELECTIVE_EXC_IP
#define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */
@@ -758,7 +760,7 @@ unwind_jump:;
} else {
PUSH(value); // push the next iteration value
}
- DISPATCH();
+ DISPATCH_WITH_PEND_EXC_CHECK();
}
// matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
diff --git a/py/vmentrytable.h b/py/vmentrytable.h
index 615f4e2ce..31a96dbec 100644
--- a/py/vmentrytable.h
+++ b/py/vmentrytable.h
@@ -24,12 +24,14 @@
* THE SOFTWARE.
*/
-#if __clang__
+#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winitializer-overrides"
#endif // __clang__
-static const void *const entry_table[256] = {
+#include "supervisor/linker.h"
+
+static const void *const PLACE_IN_DTCM_DATA(entry_table[256]) = {
[0 ... 255] = &&entry_default,
[MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE,
[MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE,
@@ -113,6 +115,6 @@ static const void *const entry_table[256] = {
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI,
};
-#if __clang__
+#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__
diff --git a/py/vstr.c b/py/vstr.c
index 869b27805..91cd7f584 100644
--- a/py/vstr.c
+++ b/py/vstr.c
@@ -50,6 +50,9 @@ void vstr_init(vstr_t *vstr, size_t alloc) {
// Init the vstr so it allocs exactly enough ram to hold a null-terminated
// string of the given length, and set the length.
void vstr_init_len(vstr_t *vstr, size_t len) {
+ if(len == SIZE_MAX) {
+ m_malloc_fail(len);
+ }
vstr_init(vstr, len + 1);
vstr->len = len;
}