summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2020-07-02 13:56:09 -0700
committerGitHub <noreply@github.com>2020-07-02 13:56:09 -0700
commitc33542f978cc61f0466ff60ea769e3067baca95f (patch)
tree071e8f8a86971f7e947053c3b4fb2ff7da95d223 /py
parentf572b723060382bbc9ca7a3edc88cb7c30fdcc30 (diff)
parenteec42d4cb53536a75e88f7f9321515bc6dcfeaa7 (diff)
Merge branch 'main' into patch-1
Diffstat (limited to 'py')
-rw-r--r--py/builtin.h7
-rw-r--r--py/builtinhelp.c4
-rw-r--r--py/builtinimport.c30
-rw-r--r--py/circuitpy_defns.mk122
-rw-r--r--py/circuitpy_mpconfig.h112
-rw-r--r--py/circuitpy_mpconfig.mk276
-rw-r--r--py/compile.c17
-rwxr-xr-xpy/gc_long_lived.c2
-rw-r--r--py/lexer.c166
-rw-r--r--py/lexer.h16
-rw-r--r--py/makeqstrdata.py55
-rw-r--r--py/mkrules.mk2
-rw-r--r--py/moduerrno.c2
-rwxr-xr-xpy/mpconfig.h9
-rw-r--r--py/obj.c6
-rw-r--r--py/obj.h1
-rw-r--r--py/objarray.c38
-rw-r--r--py/objexcept.c4
-rw-r--r--py/objmodule.c15
-rw-r--r--py/objslice.c65
-rw-r--r--py/parse.c64
-rw-r--r--py/proto.h1
-rw-r--r--py/py.mk7
-rw-r--r--py/ringbuf.c115
-rw-r--r--py/ringbuf.h83
-rw-r--r--py/runtime.c2
-rw-r--r--py/stackctrl.c4
-rw-r--r--py/stream.h2
28 files changed, 885 insertions, 342 deletions
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
index 68fa25d8d..32d364006 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -48,7 +48,6 @@ BASE_CFLAGS = \
-D__$(CHIP_VARIANT)__ \
-ffunction-sections \
-fdata-sections \
- -fshort-enums \
-DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
-DCIRCUITPY_CANARY_WORD=0xADAF00 \
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
@@ -99,6 +98,9 @@ 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
@@ -136,12 +138,21 @@ 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
@@ -151,8 +162,11 @@ endif
ifeq ($(CIRCUITPY_GAMEPADSHIFT),1)
SRC_PATTERNS += gamepadshift/%
endif
-ifeq ($(CIRCUITPY_I2CSLAVE),1)
-SRC_PATTERNS += i2cslave/%
+ifeq ($(CIRCUITPY_GNSS),1)
+SRC_PATTERNS += gnss/%
+endif
+ifeq ($(CIRCUITPY_I2CPERIPHERAL),1)
+SRC_PATTERNS += i2cperipheral/%
endif
ifeq ($(CIRCUITPY_MATH),1)
SRC_PATTERNS += math/%
@@ -178,6 +192,9 @@ 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
@@ -196,6 +213,12 @@ endif
ifeq ($(CIRCUITPY_SAMD),1)
SRC_PATTERNS += samd/%
endif
+ifeq ($(CIRCUITPY_SDCARDIO),1)
+SRC_PATTERNS += sdcardio/%
+endif
+ifeq ($(CIRCUITPY_SDIOIO),1)
+SRC_PATTERNS += sdioio/%
+endif
ifeq ($(CIRCUITPY_STAGE),1)
SRC_PATTERNS += _stage/%
endif
@@ -226,13 +249,15 @@ 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 \
@@ -242,28 +267,37 @@ SRC_COMMON_HAL_ALL = \
_bleio/PacketBuffer.c \
_bleio/Service.c \
_bleio/UUID.c \
+ _bleio/__init__.c \
+ _pew/PewPew.c \
+ _pew/__init__.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 \
+ audiobusio/__init__.c \
audioio/AudioOut.c \
+ audioio/__init__.c \
+ audiopwmio/PWMAudioOut.c \
+ audiopwmio/__init__.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 \
+ frequencyio/__init__.c \
+ gnss/__init__.c \
+ gnss/GNSS.c \
+ gnss/PositionFix.c \
+ gnss/SatelliteSystem.c \
+ i2cperipheral/I2CPeripheral.c \
+ i2cperipheral/__init__.c \
microcontroller/Pin.c \
microcontroller/Processor.c \
microcontroller/__init__.c \
@@ -271,19 +305,25 @@ SRC_COMMON_HAL_ALL = \
nvm/ByteArray.c \
nvm/__init__.c \
os/__init__.c \
+ ps2io/Ps2.c \
+ ps2io/__init__.c \
pulseio/PWMOut.c \
pulseio/PulseIn.c \
pulseio/PulseOut.c \
pulseio/__init__.c \
- ps2io/Ps2.c \
- ps2io/__init__.c \
+ rgbmatrix/RGBMatrix.c \
+ rgbmatrix/__init__.c \
rotaryio/IncrementalEncoder.c \
rotaryio/__init__.c \
rtc/RTC.c \
rtc/__init__.c \
+ sdioio/SDCard.c \
+ sdioio/__init__.c \
supervisor/Runtime.c \
supervisor/__init__.c \
- time/__init__.c
+ watchdog/WatchDogMode.c \
+ watchdog/WatchDogTimer.c \
+ watchdog/__init__.c \
SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL))
@@ -295,17 +335,16 @@ $(filter $(SRC_PATTERNS), \
_bleio/Address.c \
_bleio/Attribute.c \
_bleio/ScanEntry.c \
+ _eve/__init__.c \
digitalio/Direction.c \
digitalio/DriveMode.c \
digitalio/Pull.c \
fontio/Glyph.c \
- microcontroller/RunMode.c \
math/__init__.c \
- _eve/__init__.c \
+ microcontroller/RunMode.c \
)
SRC_BINDINGS_ENUMS += \
- help.c \
util.c
SRC_SHARED_MODULE_ALL = \
@@ -313,21 +352,24 @@ SRC_SHARED_MODULE_ALL = \
_bleio/Attribute.c \
_bleio/ScanEntry.c \
_bleio/ScanResults.c \
+ _eve/__init__.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 \
+ aesio/__init__.c \
+ aesio/aes.c \
audiocore/RawSample.c \
audiocore/WaveFile.c \
- audiomixer/__init__.c \
+ audiocore/__init__.c \
+ audioio/__init__.c \
audiomixer/Mixer.c \
audiomixer/MixerVoice.c \
- audiomp3/__init__.c \
+ audiomixer/__init__.c \
audiomp3/MP3Decoder.c \
+ audiomp3/__init__.c \
+ audiopwmio/__init__.c \
bitbangio/I2C.c \
bitbangio/OneWire.c \
bitbangio/SPI.c \
@@ -348,23 +390,32 @@ SRC_SHARED_MODULE_ALL = \
displayio/__init__.c \
fontio/BuiltinFont.c \
fontio/__init__.c \
+ framebufferio/FramebufferDisplay.c \
+ framebufferio/__init__.c \
+ sdcardio/SDCard.c \
+ sdcardio/__init__.c \
gamepad/GamePad.c \
gamepad/__init__.c \
gamepadshift/GamePadShift.c \
gamepadshift/__init__.c \
+ network/__init__.c \
os/__init__.c \
random/__init__.c \
+ rgbmatrix/RGBMatrix.c \
+ rgbmatrix/__init__.c \
socket/__init__.c \
- network/__init__.c \
storage/__init__.c \
struct/__init__.c \
terminalio/Terminal.c \
terminalio/__init__.c \
+ time/__init__.c \
uheap/__init__.c \
ustack/__init__.c \
- _pew/__init__.c \
- _pew/PewPew.c \
- _eve/__init__.c
+ vectorio/Circle.c \
+ vectorio/Polygon.c \
+ vectorio/Rectangle.c \
+ vectorio/VectorShape.c \
+ vectorio/__init__.c \
# All possible sources are listed here, and are filtered by SRC_PATTERNS.
SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL))
@@ -401,6 +452,12 @@ SRC_MOD += $(addprefix lib/mp3/src/, \
)
$(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 = \
@@ -431,6 +488,19 @@ $(addprefix lib/,\
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
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index 53cd7b0bb..d05a246fc 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -121,7 +121,9 @@
#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
//
@@ -179,14 +181,10 @@ typedef long mp_off_t;
// board-specific definitions, which control and may override definitions below.
#include "mpconfigboard.h"
-// CIRCUITPY_FULL_BUILD is defined in a *.mk file.
-
-// Remove some lesser-used functionality to make small builds fit.
+// Turning off FULL_BUILD removes some functionality to reduce flash size on tiny SAMD21s
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (CIRCUITPY_FULL_BUILD)
-//TODO: replace this with a rework of the FULL_BUILD system
-#if !defined(MICROPY_CPYTHON_COMPAT)
- #define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
-#endif
+#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)
@@ -220,13 +218,24 @@ typedef long mp_off_t;
#define MP_SSIZE_MAX (0x7fffffff)
#endif
-#if INTERNAL_FLASH_FILESYSTEM == 0 && QSPI_FLASH_FILESYSTEM == 0 && SPI_FLASH_FILESYSTEM == 0 && !CIRCUITPY_MINIMAL_BUILD
+#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;
@@ -318,6 +327,13 @@ extern const struct _mp_obj_module_t busio_module;
#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 },
@@ -342,6 +358,20 @@ extern const struct _mp_obj_module_t 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 },
@@ -371,11 +401,18 @@ extern const struct _mp_obj_module_t gamepadshift_module;
#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 },
+#if CIRCUITPY_GNSS
+extern const struct _mp_obj_module_t gnss_module;
+#define GNSS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_gnss), (mp_obj_t)&gnss_module },
+#else
+#define GNSS_MODULE
+#endif
+
+#if CIRCUITPY_I2CPERIPHERAL
+extern const struct _mp_obj_module_t i2cperipheral_module;
+#define I2CPERIPHERAL_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_i2cperipheral), (mp_obj_t)&i2cperipheral_module },
#else
-#define I2CSLAVE_MODULE
+#define I2CPERIPHERAL_MODULE
#endif
#if CIRCUITPY_MATH
@@ -451,6 +488,13 @@ extern const struct _mp_obj_module_t pixelbuf_module;
#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 },
@@ -493,6 +537,20 @@ extern const struct _mp_obj_module_t samd_module;
#define SAMD_MODULE
#endif
+#if CIRCUITPY_SDCARDIO
+extern const struct _mp_obj_module_t sdcardio_module;
+#define SDCARDIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sdcardio), (mp_obj_t)&sdcardio_module },
+#else
+#define SDCARDIO_MODULE
+#endif
+
+#if CIRCUITPY_SDIOIO
+extern const struct _mp_obj_module_t sdioio_module;
+#define SDIOIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sdioio), (mp_obj_t)&sdioio_module },
+#else
+#define SDIOIO_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 },
@@ -578,12 +636,31 @@ extern const struct _mp_obj_module_t ustack_module;
#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 \
@@ -603,6 +680,7 @@ extern const struct _mp_obj_module_t ustack_module;
// 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 \
@@ -614,15 +692,19 @@ extern const struct _mp_obj_module_t ustack_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 \
+ GNSS_MODULE \
+ I2CPERIPHERAL_MODULE \
JSON_MODULE \
MATH_MODULE \
_EVE_MODULE \
@@ -637,9 +719,12 @@ extern const struct _mp_obj_module_t ustack_module;
PULSEIO_MODULE \
RANDOM_MODULE \
RE_MODULE \
+ RGBMATRIX_MODULE \
ROTARYIO_MODULE \
RTC_MODULE \
SAMD_MODULE \
+ SDCARDIO_MODULE \
+ SDIOIO_MODULE \
STAGE_MODULE \
STORAGE_MODULE \
STRUCT_MODULE \
@@ -649,6 +734,7 @@ extern const struct _mp_obj_module_t ustack_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.
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index d6e033daf..302368f74 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -23,76 +23,32 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-# mpconfigboard.mk files can specify:
-# CIRCUITPY_FULL_BUILD = 1 (which is the default)
-# or
-# CIRCUITPY_SMALL_BUILD = 1
-# which is the same as:
-# CIRCUITPY_FULL_BUILD = 0
-
-ifndef CIRCUITPY_FULL_BUILD
- ifeq ($(CIRCUITPY_SMALL_BUILD),1)
- CIRCUITPY_FULL_BUILD = 0
- else
- CIRCUITPY_FULL_BUILD = 1
- endif
-endif
-CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD)
-
-# Setting CIRCUITPY_MINIMAL_BUILD = 1 will disable all features
-# Use for for early stage or highly restricted ports
-ifndef CIRCUITPY_MINIMAL_BUILD
-CIRCUITPY_MINIMAL_BUILD = 0
-endif
-CFLAGS += -DCIRCUITPY_MINIMAL_BUILD=$(CIRCUITPY_MINIMAL_BUILD)
-
-ifndef CIRCUITPY_DEFAULT_BUILD
- ifeq ($(CIRCUITPY_MINIMAL_BUILD),1)
- CIRCUITPY_FULL_BUILD = 0
- CIRCUITPY_DEFAULT_BUILD = 0
- else
- CIRCUITPY_DEFAULT_BUILD = 1
- endif
-endif
-CFLAGS += -DCIRCUITPY_DEFAULT_BUILD=$(CIRCUITPY_DEFAULT_BUILD)
+# Boards default to all modules enabled (with exceptions)
+# Manually disable by overriding in #mpconfigboard.mk
-# Some features have no unique HAL component, and thus there's never
-# a reason to not include them.
-ifndef CIRCUITPY_ALWAYS_BUILD
- CIRCUITPY_ALWAYS_BUILD = 1
-endif
-CFLAGS += -DCIRCUITPY_ALWAYS_BUILD=$(CIRCUITPY_ALWAYS_BUILD)
+# 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)
-# All builtin modules are listed below, with default values (0 for off, 1 for on)
-# Some are always on, some are always off, and some depend on CIRCUITPY_FULL_BUILD.
-#
-# *** You can override any of the defaults by defining them in your mpconfigboard.mk.
+CIRCUITPY_AESIO ?= 0
+CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO)
-ifndef CIRCUITPY_ANALOGIO
-CIRCUITPY_ANALOGIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_ANALOGIO ?= 1
CFLAGS += -DCIRCUITPY_ANALOGIO=$(CIRCUITPY_ANALOGIO)
-ifndef CIRCUITPY_AUDIOBUSIO
-CIRCUITPY_AUDIOBUSIO = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_AUDIOBUSIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_AUDIOBUSIO=$(CIRCUITPY_AUDIOBUSIO)
-ifndef CIRCUITPY_AUDIOIO
-CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO)
-ifndef CIRCUITPY_AUDIOIO_COMPAT
-CIRCUITPY_AUDIOIO_COMPAT = $(CIRCUITPY_AUDIOIO)
-endif
+CIRCUITPY_AUDIOIO_COMPAT ?= $(CIRCUITPY_AUDIOIO)
CFLAGS += -DCIRCUITPY_AUDIOIO_COMPAT=$(CIRCUITPY_AUDIOIO_COMPAT)
-
-ifndef CIRCUITPY_AUDIOPWMIO
-CIRCUITPY_AUDIOPWMIO = 0
-endif
+CIRCUITPY_AUDIOPWMIO ?= 0
CFLAGS += -DCIRCUITPY_AUDIOPWMIO=$(CIRCUITPY_AUDIOPWMIO)
ifndef CIRCUITPY_AUDIOCORE
@@ -104,9 +60,7 @@ endif
endif
CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE)
-ifndef CIRCUITPY_AUDIOMIXER
-CIRCUITPY_AUDIOMIXER = $(CIRCUITPY_AUDIOIO)
-endif
+CIRCUITPY_AUDIOMIXER ?= $(CIRCUITPY_AUDIOIO)
CFLAGS += -DCIRCUITPY_AUDIOMIXER=$(CIRCUITPY_AUDIOMIXER)
ifndef CIRCUITPY_AUDIOMP3
@@ -118,229 +72,175 @@ endif
endif
CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3)
-ifndef CIRCUITPY_BITBANGIO
-CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_BITBANGIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO)
# Explicitly enabled for boards that support _bleio.
-ifndef CIRCUITPY_BLEIO
-CIRCUITPY_BLEIO = 0
-endif
+CIRCUITPY_BLEIO ?= 0
CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO)
-ifndef CIRCUITPY_BOARD
-CIRCUITPY_BOARD = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_BOARD ?= 1
CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD)
-ifndef CIRCUITPY_BUSIO
-CIRCUITPY_BUSIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_BUSIO ?= 1
CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO)
-ifndef CIRCUITPY_DIGITALIO
-CIRCUITPY_DIGITALIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_DIGITALIO ?= 1
CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO)
-ifndef CIRCUITPY_DISPLAYIO
-CIRCUITPY_DISPLAYIO = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_COUNTIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO)
+
+CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO)
-ifndef CIRCUITPY_FREQUENCYIO
-CIRCUITPY_FREQUENCYIO = $(CIRCUITPY_FULL_BUILD)
-endif
+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)
-ifndef CIRCUITPY_GAMEPAD
-CIRCUITPY_GAMEPAD = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_GAMEPAD ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_GAMEPAD=$(CIRCUITPY_GAMEPAD)
-ifndef CIRCUITPY_GAMEPADSHIFT
-CIRCUITPY_GAMEPADSHIFT = 0
-endif
+CIRCUITPY_GAMEPADSHIFT ?= 0
CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
-ifndef CIRCUITPY_I2CSLAVE
-CIRCUITPY_I2CSLAVE = $(CIRCUITPY_FULL_BUILD)
-endif
-CFLAGS += -DCIRCUITPY_I2CSLAVE=$(CIRCUITPY_I2CSLAVE)
+CIRCUITPY_GNSS ?= 0
+CFLAGS += -DCIRCUITPY_GNSS=$(CIRCUITPY_GNSS)
-ifndef CIRCUITPY_MATH
-CIRCUITPY_MATH = $(CIRCUITPY_ALWAYS_BUILD)
-endif
+CIRCUITPY_I2CPERIPHERAL ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_I2CPERIPHERAL=$(CIRCUITPY_I2CPERIPHERAL)
+
+CIRCUITPY_MATH ?= 1
CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH)
-ifndef CIRCUITPY__EVE
-CIRCUITPY__EVE = 0
-endif
+CIRCUITPY__EVE ?= 0
CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
-ifndef CIRCUITPY_MICROCONTROLLER
-CIRCUITPY_MICROCONTROLLER = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_MICROCONTROLLER ?= 1
CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER)
-ifndef CIRCUITPY_NEOPIXEL_WRITE
-CIRCUITPY_NEOPIXEL_WRITE = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+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.
-ifndef CIRCUITPY_NETWORK
-CIRCUITPY_NETWORK = 0
-endif
+CIRCUITPY_NETWORK ?= 0
CFLAGS += -DCIRCUITPY_NETWORK=$(CIRCUITPY_NETWORK)
-ifndef CIRCUITPY_NVM
-CIRCUITPY_NVM = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_NVM ?= 1
CFLAGS += -DCIRCUITPY_NVM=$(CIRCUITPY_NVM)
-ifndef CIRCUITPY_OS
-CIRCUITPY_OS = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_OS ?= 1
CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS)
-ifndef CIRCUITPY_PIXELBUF
-CIRCUITPY_PIXELBUF = $(CIRCUITPY_FULL_BUILD)
-endif
+CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF)
-ifndef CIRCUITPY_PULSEIO
-CIRCUITPY_PULSEIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+# 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
-ifndef CIRCUITPY_PS2IO
-CIRCUITPY_PS2IO = 0
-endif
+CIRCUITPY_PS2IO ?= 0
CFLAGS += -DCIRCUITPY_PS2IO=$(CIRCUITPY_PS2IO)
-ifndef CIRCUITPY_RANDOM
-CIRCUITPY_RANDOM = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_RANDOM ?= 1
CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM)
-ifndef CIRCUITPY_ROTARYIO
-CIRCUITPY_ROTARYIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_ROTARYIO ?= 1
CFLAGS += -DCIRCUITPY_ROTARYIO=$(CIRCUITPY_ROTARYIO)
-ifndef CIRCUITPY_RTC
-CIRCUITPY_RTC = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+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.
-ifndef CIRCUITPY_SAMD
-CIRCUITPY_SAMD = 0
-endif
+CIRCUITPY_SAMD ?= 0
CFLAGS += -DCIRCUITPY_SAMD=$(CIRCUITPY_SAMD)
+CIRCUITPY_SDCARDIO ?= $(CIRCUITPY_FULL_BUILD)
+CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO)
+
+CIRCUITPY_SDIOIO ?= 0
+CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO)
+
# Currently always off.
-ifndef CIRCUITPY_STAGE
-CIRCUITPY_STAGE = 0
-endif
+CIRCUITPY_STAGE ?= 0
CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE)
-ifndef CIRCUITPY_STORAGE
-CIRCUITPY_STORAGE = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_STORAGE ?= 1
CFLAGS += -DCIRCUITPY_STORAGE=$(CIRCUITPY_STORAGE)
-ifndef CIRCUITPY_STRUCT
-CIRCUITPY_STRUCT = $(CIRCUITPY_ALWAYS_BUILD)
-endif
+CIRCUITPY_STRUCT ?= 1
CFLAGS += -DCIRCUITPY_STRUCT=$(CIRCUITPY_STRUCT)
-ifndef CIRCUITPY_SUPERVISOR
-CIRCUITPY_SUPERVISOR = $(CIRCUITPY_ALWAYS_BUILD)
-endif
+CIRCUITPY_SUPERVISOR ?= 1
CFLAGS += -DCIRCUITPY_SUPERVISOR=$(CIRCUITPY_SUPERVISOR)
-ifndef CIRCUITPY_TIME
-CIRCUITPY_TIME = $(CIRCUITPY_ALWAYS_BUILD)
-endif
+CIRCUITPY_TIME ?= 1
CFLAGS += -DCIRCUITPY_TIME=$(CIRCUITPY_TIME)
# touchio might be native or generic. See circuitpy_defns.mk.
-ifndef CIRCUITPY_TOUCHIO_USE_NATIVE
-CIRCUITPY_TOUCHIO_USE_NATIVE = 0
-endif
+CIRCUITPY_TOUCHIO_USE_NATIVE ?= 0
CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
-ifndef CIRCUITPY_TOUCHIO
-CIRCUITPY_TOUCHIO = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_TOUCHIO ?= 1
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
# For debugging.
-ifndef CIRCUITPY_UHEAP
-CIRCUITPY_UHEAP = 0
-endif
+CIRCUITPY_UHEAP ?= 0
CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP)
-ifndef CIRCUITPY_USB_HID
-CIRCUITPY_USB_HID = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_USB_HID ?= 1
CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
-ifndef CIRCUITPY_USB_MIDI
-CIRCUITPY_USB_MIDI = $(CIRCUITPY_DEFAULT_BUILD)
-endif
+CIRCUITPY_USB_MIDI ?= 1
CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
-ifndef CIRCUITPY_PEW
-CIRCUITPY_PEW = 0
-endif
+CIRCUITPY_PEW ?= 0
CFLAGS += -DCIRCUITPY_PEW=$(CIRCUITPY_PEW)
# For debugging.
-ifndef CIRCUITPY_USTACK
-CIRCUITPY_USTACK = 0
-endif
+CIRCUITPY_USTACK ?= 0
CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK)
# Non-module conditionals
-ifndef CIRCUITPY_BITBANG_APA102
-CIRCUITPY_BITBANG_APA102 = 0
-endif
+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.
-ifndef CIRCUITPY_REQUIRE_I2C_PULLUPS
-CIRCUITPY_REQUIRE_I2C_PULLUPS = 1
-endif
+CIRCUITPY_REQUIRE_I2C_PULLUPS ?= 1
CFLAGS += -DCIRCUITPY_REQUIRE_I2C_PULLUPS=$(CIRCUITPY_REQUIRE_I2C_PULLUPS)
# REPL over BLE
-ifndef CIRCUITPY_SERIAL_BLE
-CIRCUITPY_SERIAL_BLE = 0
-endif
+CIRCUITPY_SERIAL_BLE ?= 0
CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE)
-ifndef CIRCUITPY_BLE_FILE_SERVICE
-CIRCUITPY_BLE_FILE_SERVICE = 0
-endif
+CIRCUITPY_BLE_FILE_SERVICE ?= 0
CFLAGS += -DCIRCUITPY_BLE_FILE_SERVICE=$(CIRCUITPY_BLE_FILE_SERVICE)
# REPL over UART
-ifndef CIRCUITPY_SERIAL_UART
-CIRCUITPY_SERIAL_UART = 0
-endif
+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)
-ifndef CIRCUITPY_ENABLE_MPY_NATIVE
-CIRCUITPY_ENABLE_MPY_NATIVE = 0
-endif
+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 77715d3fe..d5fae0299 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1711,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);
@@ -1720,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);
@@ -1857,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);
diff --git a/py/gc_long_lived.c b/py/gc_long_lived.c
index 01c22a7af..0e94390e9 100755
--- a/py/gc_long_lived.c
+++ b/py/gc_long_lived.c
@@ -89,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 || dict == &MP_STATE_VM(dict_main)) {
+ 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.
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/makeqstrdata.py b/py/makeqstrdata.py
index 0d667959d..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
@@ -132,19 +135,37 @@ def compute_huffman_coding(translations, qstrs, compression_filename):
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 {} 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 = []
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]
@@ -170,10 +191,11 @@ def decompress(encoding_table, length, encoded):
searched_length += lengths[bit_length]
v = values[searched_length + bits - max_code]
+ i += len(v.encode('utf-8'))
dec.append(v)
return ''.join(dec)
-def compress(encoding_table, decompressed):
+def compress(encoding_table, decompressed, encoded_length_bits, len_translation_encoded):
if not isinstance(decompressed, str):
raise TypeError()
values, lengths = encoding_table
@@ -182,6 +204,19 @@ def compress(encoding_table, 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))
@@ -342,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)
+ 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)
+ 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()
@@ -385,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/mkrules.mk b/py/mkrules.mk
index 292d25746..13a73b90e 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -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/moduerrno.c b/py/moduerrno.c
index 7915603e4..3be5adba1 100644
--- a/py/moduerrno.c
+++ b/py/moduerrno.c
@@ -158,7 +158,7 @@ const char *mp_common_errno_to_str(mp_obj_t errno_val, char *buf, size_t len) {
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 1512c7d3a..513f04f6e 100755
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -377,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 */
@@ -1173,6 +1178,10 @@ 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
diff --git a/py/obj.c b/py/obj.c
index f1e00de1a..4fa2032dc 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -94,17 +94,17 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
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
diff --git a/py/obj.h b/py/obj.h
index cf4216d02..fa315d12f 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -858,6 +858,7 @@ 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);
diff --git a/py/objarray.c b/py/objarray.c
index 9114a63c5..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
@@ -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
diff --git a/py/objexcept.c b/py/objexcept.c
index b7a536c5e..796be122f 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -400,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;
@@ -433,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';
diff --git a/py/objmodule.c b/py/objmodule.c
index 627ba79e8..b6a8a084e 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -69,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) {
@@ -206,6 +213,14 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
{ 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.
diff --git a/py/objslice.c b/py/objslice.c
index 5a15be55a..cbbee326e 100644
--- a/py/objslice.c
+++ b/py/objslice.c
@@ -152,6 +152,71 @@ 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, const mp_obj_t *args, mp_map_t *kw_args) {
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/proto.h b/py/proto.h
index 2d4f80565..fadf1f882 100644
--- a/py/proto.h
+++ b/py/proto.h
@@ -40,4 +40,3 @@ 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 a73b47f37..3cb505920 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -105,6 +105,12 @@ $(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
@@ -240,6 +246,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
repl.o \
smallint.o \
frozenmod.o \
+ ringbuf.o \
)
PY_EXTMOD_O_BASENAME = \
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 7fc35d266..476bd428f 100644
--- a/py/ringbuf.h
+++ b/py/ringbuf.h
@@ -32,78 +32,27 @@
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, long_lived) \
-{ \
- (r)->buf = gc_alloc(sz, false, long_lived); \
- (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;
-}
-
-static inline uint16_t ringbuf_count(ringbuf_t *r)
-{
- volatile int count = r->iput - r->iget;
- if ( count < 0 ) {
- count += r->size;
- }
-
- return (uint16_t) count;
-}
-
-static inline void ringbuf_clear(ringbuf_t *r)
-{
- r->iput = r->iget = 0;
-}
-
-// will overwrite old data
-static inline void ringbuf_put_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize)
-{
- for(uint8_t i=0; i < bufsize; i++) {
- if ( ringbuf_put(r, buf[i]) < 0 ) {
- // if full overwrite old data
- (void) ringbuf_get(r);
- ringbuf_put(r, buf[i]);
- }
- }
-}
+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);
-static inline void ringbuf_get_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize)
-{
- for(uint8_t i=0; i < bufsize; i++) {
- buf[i] = ringbuf_get(r);
- }
-}
#endif // MICROPY_INCLUDED_PY_RINGBUF_H
diff --git a/py/runtime.c b/py/runtime.c
index c1c311ae4..59dcbc7a1 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1172,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));
}
}
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.h b/py/stream.h
index 543fe8c82..dc9fc84c9 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -95,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 mp_proto_get(MP_QSTR_protocol_stream, self);
+ 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);