commit
918145f768
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -72,10 +72,10 @@ jobs:
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --emit native
|
||||
working-directory: tests
|
||||
- name: mpy Tests
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy -d basics float micropython
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy -d basics float micropython
|
||||
working-directory: tests
|
||||
- name: Native mpy Tests
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy --emit native -d basics float micropython
|
||||
working-directory: tests
|
||||
- name: Build native modules
|
||||
run: |
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2021 Damien P. George
|
||||
Copyright (c) 2013-2022 Damien P. George
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,11 +21,11 @@ For example::
|
||||
import framebuf
|
||||
|
||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||
fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
|
||||
fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565)
|
||||
|
||||
fbuf.fill(0)
|
||||
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
||||
fbuf.hline(0, 10, 96, 0xffff)
|
||||
fbuf.hline(0, 9, 96, 0xffff)
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
@ -80,6 +80,14 @@ Constants
|
||||
|
||||
A mutable list of directories to search for imported modules.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
On MicroPython, an entry with the value ``".frozen"`` will indicate that import
|
||||
should search :term:`frozen modules <frozen module>` at that point in the search.
|
||||
If no frozen module is found then search will *not* look for a directory called
|
||||
``.frozen``, instead it will continue with the next entry in ``sys.path``.
|
||||
|
||||
.. data:: platform
|
||||
|
||||
The platform that CircuitPython is running on. For OS/RTOS ports, this is
|
||||
|
@ -10,11 +10,13 @@ set(MICROPY_SOURCE_EXTMOD
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2c.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_mem.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_pulse.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_pwm.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_signal.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_spi.c
|
||||
${MICROPY_EXTMOD_DIR}/modbluetooth.c
|
||||
${MICROPY_EXTMOD_DIR}/modbtree.c
|
||||
${MICROPY_EXTMOD_DIR}/modframebuf.c
|
||||
${MICROPY_EXTMOD_DIR}/modnetwork.c
|
||||
${MICROPY_EXTMOD_DIR}/modonewire.c
|
||||
${MICROPY_EXTMOD_DIR}/moduasyncio.c
|
||||
${MICROPY_EXTMOD_DIR}/modubinascii.c
|
||||
@ -23,9 +25,11 @@ set(MICROPY_SOURCE_EXTMOD
|
||||
${MICROPY_EXTMOD_DIR}/moduhashlib.c
|
||||
${MICROPY_EXTMOD_DIR}/moduheapq.c
|
||||
${MICROPY_EXTMOD_DIR}/modujson.c
|
||||
${MICROPY_EXTMOD_DIR}/moduplatform.c
|
||||
${MICROPY_EXTMOD_DIR}/modurandom.c
|
||||
${MICROPY_EXTMOD_DIR}/modure.c
|
||||
${MICROPY_EXTMOD_DIR}/moduselect.c
|
||||
${MICROPY_EXTMOD_DIR}/modusocket.c
|
||||
${MICROPY_EXTMOD_DIR}/modussl_axtls.c
|
||||
${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
|
||||
${MICROPY_EXTMOD_DIR}/modutimeq.c
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#if MICROPY_PY_ONEWIRE
|
||||
|
||||
/******************************************************************************/
|
||||
// Low-level 1-Wire routines
|
||||
|
||||
@ -139,3 +141,5 @@ const mp_obj_module_t mp_module_onewire = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&onewire_module_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_ONEWIRE
|
||||
|
146
extmod/moduplatform.c
Normal file
146
extmod/moduplatform.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||
*
|
||||
* 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/runtime.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/mphal.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
|
||||
#if MICROPY_PY_UPLATFORM
|
||||
|
||||
// platform - Access to underlying platform's identifying data
|
||||
|
||||
// TODO: Add more architectures, compilers and libraries.
|
||||
// See: https://sourceforge.net/p/predef/wiki/Home/
|
||||
|
||||
#if defined(__ARM_ARCH)
|
||||
#define PLATFORM_ARCH "arm"
|
||||
#elif defined(__x86_64__) || defined(_WIN64)
|
||||
#define PLATFORM_ARCH "x86_64"
|
||||
#elif defined(__i386__) || defined(_M_IX86)
|
||||
#define PLATFORM_ARCH "x86"
|
||||
#elif defined(__xtensa__) || defined(_M_IX86)
|
||||
#define PLATFORM_ARCH "xtensa"
|
||||
#else
|
||||
#define PLATFORM_ARCH ""
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define PLATFORM_COMPILER \
|
||||
"GCC " \
|
||||
MP_STRINGIFY(__GNUC__) "." \
|
||||
MP_STRINGIFY(__GNUC_MINOR__) "." \
|
||||
MP_STRINGIFY(__GNUC_PATCHLEVEL__)
|
||||
#elif defined(__ARMCC_VERSION)
|
||||
#define PLATFORM_COMPILER \
|
||||
"ARMCC " \
|
||||
MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
|
||||
MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
|
||||
MP_STRINGIFY((__ARMCC_VERSION % 10000))
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_WIN64)
|
||||
#define COMPILER_BITS "64 bit"
|
||||
#elif defined(_M_IX86)
|
||||
#define COMPILER_BITS "32 bit"
|
||||
#else
|
||||
#define COMPILER_BITS ""
|
||||
#endif
|
||||
#define PLATFORM_COMPILER \
|
||||
"MSC v." MP_STRINGIFY(_MSC_VER) " " COMPILER_BITS
|
||||
#else
|
||||
#define PLATFORM_COMPILER ""
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
#define PLATFORM_LIBC_LIB "glibc"
|
||||
#define PLATFORM_LIBC_VER \
|
||||
MP_STRINGIFY(__GLIBC__) "." \
|
||||
MP_STRINGIFY(__GLIBC_MINOR__)
|
||||
#elif defined(__NEWLIB__)
|
||||
#define PLATFORM_LIBC_LIB "newlib"
|
||||
#define PLATFORM_LIBC_VER _NEWLIB_VERSION
|
||||
#else
|
||||
#define PLATFORM_LIBC_LIB ""
|
||||
#define PLATFORM_LIBC_VER ""
|
||||
#endif
|
||||
|
||||
#if defined(__linux)
|
||||
#define PLATFORM_SYSTEM "Linux"
|
||||
#elif defined(__unix__)
|
||||
#define PLATFORM_SYSTEM "Unix"
|
||||
#elif defined(__CYGWIN__)
|
||||
#define PLATFORM_SYSTEM "Cygwin"
|
||||
#elif defined(_WIN32)
|
||||
#define PLATFORM_SYSTEM "Windows"
|
||||
#else
|
||||
#define PLATFORM_SYSTEM "MicroPython"
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PLATFORM_VERSION
|
||||
#define MICROPY_PLATFORM_VERSION ""
|
||||
#endif
|
||||
|
||||
STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-" \
|
||||
PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
|
||||
STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);
|
||||
STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB);
|
||||
STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER);
|
||||
STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
|
||||
{&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
|
||||
};
|
||||
|
||||
STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
return MP_OBJ_FROM_PTR(&info_platform_obj);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
|
||||
|
||||
STATIC mp_obj_t platform_python_compiler(void) {
|
||||
return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
|
||||
|
||||
STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
|
||||
|
||||
STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uplatform = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&modplatform_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_UPLATFORM
|
@ -477,11 +477,16 @@ MP_REGISTER_MODULE(MP_QSTR_re, mp_module_ure, MICROPY_PY_URE);
|
||||
// only if module is enabled by config setting.
|
||||
|
||||
#define re1_5_fatal(x) assert(!x)
|
||||
|
||||
#include "lib/re1.5/compilecode.c"
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
#include "lib/re1.5/dumpcode.c"
|
||||
#endif
|
||||
#include "lib/re1.5/recursiveloop.c"
|
||||
#include "lib/re1.5/charclass.c"
|
||||
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
// Make sure the output print statements go to the same output as other Python output.
|
||||
#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
|
||||
#include "lib/re1.5/dumpcode.c"
|
||||
#undef printf
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_URE
|
||||
|
@ -36,7 +36,7 @@ class SingletonGenerator:
|
||||
self.state = None
|
||||
self.exc = StopIteration()
|
||||
|
||||
def __iter__(self):
|
||||
def __await__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
|
@ -66,7 +66,7 @@ async def gather(*aws, return_exceptions=False):
|
||||
# # cancel all waiting tasks
|
||||
# raise er
|
||||
ts[i] = await ts[i]
|
||||
except Exception as er:
|
||||
except (core.CancelledError, Exception) as er:
|
||||
if return_exceptions:
|
||||
ts[i] = er
|
||||
else:
|
||||
|
@ -130,7 +130,7 @@ class Task:
|
||||
self.ph_next = None # Paring heap
|
||||
self.ph_rightmost_parent = None # Paring heap
|
||||
|
||||
def __iter__(self):
|
||||
def __await__(self):
|
||||
if not self.state:
|
||||
# Task finished, signal that is has been await'ed on.
|
||||
self.state = False
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#define fsync _commit
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
typedef struct _mp_obj_vfs_posix_file_t {
|
||||
@ -180,6 +182,32 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||
return 0;
|
||||
case MP_STREAM_GET_FILENO:
|
||||
return o->fd;
|
||||
#if MICROPY_PY_USELECT
|
||||
case MP_STREAM_POLL: {
|
||||
#ifdef _WIN32
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
|
||||
#else
|
||||
mp_uint_t ret = 0;
|
||||
uint8_t pollevents = 0;
|
||||
if (arg & MP_STREAM_POLL_RD) {
|
||||
pollevents |= POLLIN;
|
||||
}
|
||||
if (arg & MP_STREAM_POLL_WR) {
|
||||
pollevents |= POLLOUT;
|
||||
}
|
||||
struct pollfd pfd = { .fd = o->fd, .events = pollevents };
|
||||
if (poll(&pfd, 1, 0) > 0) {
|
||||
if (pfd.revents & POLLIN) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
if (pfd.revents & POLLOUT) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
*errcode = EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
|
@ -2886,6 +2886,10 @@ msgstr ""
|
||||
msgid "can't load with '%q' index"
|
||||
msgstr ""
|
||||
|
||||
#: py/builtinimport.c
|
||||
msgid "can't perform relative import"
|
||||
msgstr ""
|
||||
|
||||
#: py/objgenerator.c
|
||||
msgid "can't send non-None value to a just-started generator"
|
||||
msgstr ""
|
||||
@ -2948,10 +2952,6 @@ msgstr ""
|
||||
msgid "cannot import name %q"
|
||||
msgstr ""
|
||||
|
||||
#: py/builtinimport.c
|
||||
msgid "cannot perform relative import"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/moductypes.c
|
||||
msgid "cannot unambiguously get sizeof scalar"
|
||||
msgstr ""
|
||||
@ -3642,7 +3642,7 @@ msgstr ""
|
||||
msgid "matrix is not positive definite"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/wifi/Radio.c
|
||||
#: ports/espressif/common-hal/wifi/Radio.c
|
||||
msgid "max_connections must be between 0 and 10"
|
||||
msgstr ""
|
||||
|
||||
@ -4023,6 +4023,10 @@ msgstr ""
|
||||
msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/vfs_posix_file.c
|
||||
msgid "poll on file not available on win32"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/vectorio/Polygon.c
|
||||
msgid "polygon can only be registered in one parent"
|
||||
msgstr ""
|
||||
@ -4068,6 +4072,7 @@ msgstr ""
|
||||
#: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
|
||||
#: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
|
||||
#: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
|
||||
#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
|
||||
#: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
|
||||
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
|
||||
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
|
||||
|
6
main.c
6
main.c
@ -162,9 +162,9 @@ STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
|
||||
mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0);
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
|
||||
// Frozen modules are in their own pseudo-dir, e.g., ".frozen".
|
||||
// Prioritize .frozen over /lib.
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR));
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
|
||||
#endif
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
|
||||
|
||||
mp_obj_list_init((mp_obj_list_t *)mp_sys_argv, 0);
|
||||
|
@ -23,10 +23,7 @@ by the target MicroPython runtime (eg onto a pyboard's filesystem), and then
|
||||
imported like any other Python module using `import foo`.
|
||||
|
||||
Different target runtimes may require a different format of the compiled
|
||||
bytecode, and such options can be passed to the cross compiler. For example,
|
||||
the unix port of MicroPython requires the following:
|
||||
|
||||
$ ./mpy-cross -mcache-lookup-bc foo.py
|
||||
bytecode, and such options can be passed to the cross compiler.
|
||||
|
||||
If the Python code contains `@native` or `@viper` annotations, then you must
|
||||
specify `-march` to match the target architecture.
|
||||
|
@ -87,7 +87,6 @@ STATIC int usage(char **argv) {
|
||||
"Target specific options:\n"
|
||||
"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
|
||||
"-mno-unicode : don't support unicode in compiled strings\n"
|
||||
"-mcache-lookup-bc : cache map lookups in the bytecode\n"
|
||||
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
|
||||
"\n"
|
||||
"Implementation specific options:\n", argv[0]
|
||||
@ -172,8 +171,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
#ifdef _WIN32
|
||||
set_fmode_binary();
|
||||
#endif
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
// Set default emitter options
|
||||
@ -184,7 +181,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
|
||||
// set default compiler configuration
|
||||
mp_dynamic_compiler.small_int_bits = 31;
|
||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
|
||||
mp_dynamic_compiler.py_builtins_str_unicode = 1;
|
||||
#if defined(__i386__)
|
||||
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
|
||||
@ -243,10 +239,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
return usage(argv);
|
||||
}
|
||||
// TODO check that small_int_bits is within range of host's capabilities
|
||||
} else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) {
|
||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
|
||||
} else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) {
|
||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1;
|
||||
} else if (strcmp(argv[a], "-mno-unicode") == 0) {
|
||||
mp_dynamic_compiler.py_builtins_str_unicode = 0;
|
||||
} else if (strcmp(argv[a], "-municode") == 0) {
|
||||
|
@ -36,8 +36,6 @@
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
|
||||
#define MICROPY_READER_POSIX (1)
|
||||
#define MICROPY_ENABLE_RUNTIME (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
|
@ -13,6 +13,9 @@ include ../../py/mkenv.mk
|
||||
-include mpconfigport.mk
|
||||
include $(VARIANT_DIR)/mpconfigvariant.mk
|
||||
|
||||
# Use the default frozen manifest, variants may override this.
|
||||
FROZEN_MANIFEST ?= variants/manifest.py
|
||||
|
||||
# This should be configured by the mpconfigvariant.mk
|
||||
PROG ?= micropython
|
||||
|
||||
@ -39,7 +42,7 @@ CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DI
|
||||
|
||||
# Debugging/Optimization
|
||||
ifdef DEBUG
|
||||
COPT ?= -O0
|
||||
COPT ?= -Og
|
||||
else
|
||||
COPT ?= -Os
|
||||
COPT += -DNDEBUG
|
||||
@ -256,12 +259,14 @@ SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
|
||||
# SRC_QSTR
|
||||
SRC_QSTR_AUTO_DEPS +=
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIR),)
|
||||
ifneq ($(FROZEN_MANIFEST),)
|
||||
# To use frozen code create a manifest.py file with a description of files to
|
||||
# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch).
|
||||
CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
|
||||
CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
|
||||
CFLAGS += -DMICROPY_MODULE_FROZEN_STR
|
||||
CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
|
||||
MPY_CROSS_FLAGS += -mcache-lookup-bc
|
||||
CFLAGS += -DMICROPY_MODULE_FROZEN_STR
|
||||
endif
|
||||
|
||||
HASCPP17 = $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 7)
|
||||
@ -273,9 +278,7 @@ endif
|
||||
CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99 -std=gnu11,$(CFLAGS) $(CXXFLAGS_MOD))
|
||||
|
||||
ifeq ($(MICROPY_FORCE_32BIT),1)
|
||||
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86'
|
||||
else
|
||||
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc'
|
||||
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86'
|
||||
endif
|
||||
|
||||
ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-)
|
||||
|
@ -161,7 +161,7 @@ STATIC void pairheap_test(size_t nops, int *ops) {
|
||||
mp_pairheap_init_node(pairheap_lt, &node[i]);
|
||||
}
|
||||
mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt);
|
||||
printf("create:");
|
||||
mp_printf(&mp_plat_print, "create:");
|
||||
for (size_t i = 0; i < nops; ++i) {
|
||||
if (ops[i] >= 0) {
|
||||
heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]);
|
||||
@ -175,13 +175,13 @@ STATIC void pairheap_test(size_t nops, int *ops) {
|
||||
;
|
||||
}
|
||||
}
|
||||
printf("\npop all:");
|
||||
mp_printf(&mp_plat_print, "\npop all:");
|
||||
while (!mp_pairheap_is_empty(pairheap_lt, heap)) {
|
||||
mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);
|
||||
;
|
||||
heap = mp_pairheap_pop(pairheap_lt, heap);
|
||||
}
|
||||
printf("\n");
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
||||
|
||||
// function to run extra tests for things that can't be checked by scripts
|
||||
|
@ -494,16 +494,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
char *home = getenv("HOME");
|
||||
char *path = getenv("MICROPYPATH");
|
||||
if (path == NULL) {
|
||||
#ifdef MICROPY_PY_SYS_PATH_DEFAULT
|
||||
path = MICROPY_PY_SYS_PATH_DEFAULT;
|
||||
#else
|
||||
path = "~/.micropython/lib:/usr/lib/micropython";
|
||||
#endif
|
||||
}
|
||||
size_t path_num = 2; // [0] is for current dir (or base dir of the script)
|
||||
// [1] is for frozen files.
|
||||
size_t builtin_path_count = path_num;
|
||||
if (*path == ':') {
|
||||
size_t path_num = 1; // [0] is for current dir (or base dir of the script)
|
||||
if (*path == PATHLIST_SEP_CHAR) {
|
||||
path_num++;
|
||||
}
|
||||
for (char *p = path; p != NULL; p = strchr(p, PATHLIST_SEP_CHAR)) {
|
||||
@ -516,11 +510,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
mp_obj_t *path_items;
|
||||
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
|
||||
path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
// Frozen modules are in their own pseudo-dir, e.g., ".frozen".
|
||||
path_items[1] = MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR);
|
||||
{
|
||||
char *p = path;
|
||||
for (mp_uint_t i = builtin_path_count; i < path_num; i++) {
|
||||
for (mp_uint_t i = 1; i < path_num; i++) {
|
||||
char *p1 = strchr(p, PATHLIST_SEP_CHAR);
|
||||
if (p1 == NULL) {
|
||||
p1 = p + strlen(p);
|
||||
@ -661,7 +653,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Set base dir of the script as first entry in sys.path
|
||||
// Set base dir of the script as first entry in sys.path.
|
||||
char *p = strrchr(basedir, '/');
|
||||
path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
|
||||
free(pathbuf);
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -48,6 +49,29 @@
|
||||
#define USE_STATFS 1
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
|
||||
#if __GLIBC_PREREQ(2, 25)
|
||||
#include <sys/random.h>
|
||||
#define _HAVE_GETRANDOM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n);
|
||||
#ifdef _HAVE_GETRANDOM
|
||||
RAISE_ERRNO(getrandom(vstr.buf, n, 0), errno);
|
||||
#else
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
RAISE_ERRNO(fd, errno);
|
||||
RAISE_ERRNO(read(fd, vstr.buf, n), errno);
|
||||
close(fd);
|
||||
#endif
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_urandom_obj, mod_os_urandom);
|
||||
|
||||
STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) {
|
||||
struct stat sb;
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
@ -308,6 +332,7 @@ STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mod_os_urandom_obj) },
|
||||
#if MICROPY_PY_OS_STATVFS
|
||||
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) },
|
||||
#endif
|
||||
|
@ -80,10 +80,14 @@
|
||||
#endif
|
||||
#define MICROPY_STREAMS_POSIX_API (1)
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (1)
|
||||
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
|
||||
#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
|
||||
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
|
||||
#endif
|
||||
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
|
||||
#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
|
||||
#endif
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_VFS_POSIX_FILE (1)
|
||||
#define MICROPY_PY_FUNCTION_ATTRS (1)
|
||||
@ -107,6 +111,8 @@
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE_INDICES (1)
|
||||
#define MICROPY_PY_SYS_ATEXIT (1)
|
||||
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
|
||||
#define MICROPY_PY_SYS_EXIT (1)
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
#define MICROPY_PERSISTENT_CODE_SAVE (1)
|
||||
@ -119,6 +125,9 @@
|
||||
#define MICROPY_PY_SYS_PLATFORM "linux"
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MICROPY_PY_SYS_PATH_DEFAULT
|
||||
#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
|
||||
#endif
|
||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||
#define MICROPY_PY_SYS_STDFILES (1)
|
||||
#define MICROPY_PY_SYS_EXC_INFO (1)
|
||||
|
@ -51,7 +51,6 @@
|
||||
#define MICROPY_PY_MATH_FACTORIAL (1)
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
|
||||
#define MICROPY_PY_IO_BUFFEREDWRITER (1)
|
||||
#define MICROPY_PY_IO_RESOURCE_STREAM (1)
|
||||
#define MICROPY_PY_UASYNCIO (1)
|
||||
#define MICROPY_PY_URE_DEBUG (1)
|
||||
#define MICROPY_PY_URE_MATCH_GROUPS (1)
|
||||
|
@ -12,15 +12,13 @@ CFLAGS += \
|
||||
|
||||
LDFLAGS += -fprofile-arcs -ftest-coverage
|
||||
|
||||
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
|
||||
USER_C_MODULES = $(TOP)/examples/usercmodule
|
||||
|
||||
MICROPY_VFS_FAT = 1
|
||||
MICROPY_VFS_LFS1 = 1
|
||||
MICROPY_VFS_LFS2 = 1
|
||||
|
||||
FROZEN_DIR=variants/coverage/frzstr
|
||||
FROZEN_MPY_DIR=variants/coverage/frzmpy
|
||||
|
||||
SRC_QRIO := $(patsubst ../../%,%,$(wildcard ../../shared-bindings/qrio/*.c ../../shared-module/qrio/*.c ../../lib/quirc/lib/*.c))
|
||||
SRC_C += $(SRC_QRIO)
|
||||
|
||||
|
@ -55,7 +55,8 @@
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
|
||||
#define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
@ -87,6 +88,9 @@
|
||||
#define MICROPY_PY_SYS (1)
|
||||
#define MICROPY_PY_SYS_EXIT (0)
|
||||
#define MICROPY_PY_SYS_PLATFORM "linux"
|
||||
#ifndef MICROPY_PY_SYS_PATH_DEFAULT
|
||||
#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
|
||||
#endif
|
||||
#define MICROPY_PY_SYS_MAXSIZE (0)
|
||||
#define MICROPY_PY_SYS_STDFILES (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
|
14
py/bc.c
14
py/bc.c
@ -314,24 +314,10 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
||||
|
||||
// The following table encodes the number of bytes that a specific opcode
|
||||
// takes up. Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE.
|
||||
// There are 4 special opcodes that have an extra byte only when
|
||||
// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr):
|
||||
// MP_BC_LOAD_NAME
|
||||
// MP_BC_LOAD_GLOBAL
|
||||
// MP_BC_LOAD_ATTR
|
||||
// MP_BC_STORE_ATTR
|
||||
uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) {
|
||||
uint f = MP_BC_FORMAT(*ip);
|
||||
const byte *ip_start = ip;
|
||||
if (f == MP_BC_FORMAT_QSTR) {
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
|
||||
if (*ip == MP_BC_LOAD_NAME
|
||||
|| *ip == MP_BC_LOAD_GLOBAL
|
||||
|| *ip == MP_BC_LOAD_ATTR
|
||||
|| *ip == MP_BC_STORE_ATTR) {
|
||||
ip += 1;
|
||||
}
|
||||
}
|
||||
ip += 3;
|
||||
} else {
|
||||
int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0;
|
||||
|
@ -119,13 +119,8 @@ extern const mp_obj_module_t mp_module_utimeq;
|
||||
extern const mp_obj_module_t mp_module_machine;
|
||||
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 mp_obj_module_t mp_module_ubluetooth;
|
||||
extern const mp_obj_module_t mp_module_uplatform;
|
||||
|
||||
extern const char MICROPY_PY_BUILTINS_HELP_TEXT[];
|
||||
|
||||
|
@ -69,22 +69,18 @@ STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) {
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {
|
||||
while (*name) {
|
||||
size_t l = strlen(name);
|
||||
size_t len = strlen(name);
|
||||
// name should end in '.py' and we strip it off
|
||||
mp_obj_list_append(list, mp_obj_new_str(name, l - 3));
|
||||
name += l + 1;
|
||||
mp_obj_list_append(list, mp_obj_new_str(name, len - 3));
|
||||
name += len + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// These externs were originally declared inside mp_help_print_modules(),
|
||||
// but they triggered -Wnested-externs, so they were moved outside.
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
extern const char mp_frozen_str_names[];
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
extern const char mp_frozen_mpy_names[];
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
extern const char mp_frozen_names[];
|
||||
#endif
|
||||
|
||||
STATIC void mp_help_print_modules(void) {
|
||||
@ -92,12 +88,8 @@ STATIC void mp_help_print_modules(void) {
|
||||
|
||||
mp_help_add_from_map(list, &mp_builtin_module_map);
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
mp_help_add_from_names(list, mp_frozen_str_names);
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
mp_help_add_from_names(list, mp_frozen_mpy_names);
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
mp_help_add_from_names(list, mp_frozen_names);
|
||||
#endif
|
||||
|
||||
// sort the list so it's printed in alphabetical order
|
||||
|
@ -5,6 +5,7 @@
|
||||
*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2013-2019 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
* Copyright (c) 2021 Jim Mussared
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -50,7 +51,11 @@
|
||||
|
||||
#if MICROPY_ENABLE_EXTERNAL_IMPORT
|
||||
|
||||
#define PATH_SEP_CHAR '/'
|
||||
// Must be a string of one byte.
|
||||
#define PATH_SEP_CHAR "/"
|
||||
|
||||
// Virtual sys.path entry that maps to the frozen modules.
|
||||
#define MP_FROZEN_PATH_PREFIX ".frozen/"
|
||||
|
||||
bool mp_obj_is_package(mp_obj_t module) {
|
||||
mp_obj_t dest[2];
|
||||
@ -58,31 +63,33 @@ bool mp_obj_is_package(mp_obj_t module) {
|
||||
return dest[0] != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// Stat either frozen or normal module by a given path
|
||||
// (whatever is available, if at all).
|
||||
STATIC mp_import_stat_t mp_import_stat_any(const char *path) {
|
||||
// Wrapper for mp_import_stat (which is provided by the port, and typically
|
||||
// uses mp_vfs_import_stat) to also search frozen modules. Given an exact
|
||||
// path to a file or directory (e.g. "foo/bar", foo/bar.py" or "foo/bar.mpy"),
|
||||
// will return whether the path is a file, directory, or doesn't exist.
|
||||
STATIC mp_import_stat_t stat_path_or_frozen(const char *path) {
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
if (strncmp(MP_FROZEN_FAKE_DIR_SLASH,
|
||||
path,
|
||||
MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
|
||||
mp_import_stat_t st = mp_frozen_stat(path + MP_FROZEN_FAKE_DIR_SLASH_LENGTH);
|
||||
if (st != MP_IMPORT_STAT_NO_EXIST) {
|
||||
return st;
|
||||
}
|
||||
// Only try and load as a frozen module if it starts with .frozen/.
|
||||
const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
|
||||
if (strncmp(path, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
|
||||
return mp_find_frozen_module(path + frozen_path_prefix_len, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
return mp_import_stat(path);
|
||||
}
|
||||
|
||||
// Given a path to a .py file, try and find this path as either a .py or .mpy
|
||||
// in either the filesystem or frozen modules.
|
||||
STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
|
||||
mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
|
||||
mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
|
||||
if (stat == MP_IMPORT_STAT_FILE) {
|
||||
return stat;
|
||||
}
|
||||
|
||||
#if MICROPY_PERSISTENT_CODE_LOAD
|
||||
// Didn't find .py -- try the .mpy instead by inserting an 'm' into the '.py'.
|
||||
vstr_ins_byte(path, path->len - 2, 'm');
|
||||
stat = mp_import_stat_any(vstr_null_terminated_str(path));
|
||||
stat = stat_path_or_frozen(vstr_null_terminated_str(path));
|
||||
if (stat == MP_IMPORT_STAT_FILE) {
|
||||
return stat;
|
||||
}
|
||||
@ -91,8 +98,10 @@ STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
// Given an import path (e.g. "foo/bar"), try and find "foo/bar" (a directory)
|
||||
// or "foo/bar.(m)py" in either the filesystem or frozen modules.
|
||||
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
|
||||
mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
|
||||
DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
return stat;
|
||||
@ -103,40 +112,41 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
return stat_file_py_or_mpy(path);
|
||||
}
|
||||
|
||||
STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
// Given a top-level module, try and find it in each of the sys.path entries
|
||||
// via stat_dir_or_file.
|
||||
STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) {
|
||||
DEBUG_printf("stat_top_level_dir_or_file: '%s'\n", qstr_str(mod_name));
|
||||
#if MICROPY_PY_SYS
|
||||
// extract the list of paths
|
||||
size_t path_num;
|
||||
mp_obj_t *path_items;
|
||||
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
|
||||
|
||||
if (path_num == 0) {
|
||||
#endif
|
||||
// mp_sys_path is empty, so just use the given file name
|
||||
vstr_add_strn(dest, file_str, file_len);
|
||||
return stat_dir_or_file(dest);
|
||||
#if MICROPY_PY_SYS
|
||||
} else {
|
||||
// go through each path looking for a directory or file
|
||||
for (size_t i = 0; i < path_num; i++) {
|
||||
vstr_reset(dest);
|
||||
size_t p_len;
|
||||
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
|
||||
if (p_len > 0) {
|
||||
vstr_add_strn(dest, p, p_len);
|
||||
vstr_add_char(dest, PATH_SEP_CHAR);
|
||||
if (path_num > 0) {
|
||||
// go through each path looking for a directory or file
|
||||
for (size_t i = 0; i < path_num; i++) {
|
||||
vstr_reset(dest);
|
||||
size_t p_len;
|
||||
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
|
||||
if (p_len > 0) {
|
||||
vstr_add_strn(dest, p, p_len);
|
||||
vstr_add_char(dest, PATH_SEP_CHAR[0]);
|
||||
}
|
||||
vstr_add_str(dest, qstr_str(mod_name));
|
||||
mp_import_stat_t stat = stat_dir_or_file(dest);
|
||||
if (stat != MP_IMPORT_STAT_NO_EXIST) {
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
vstr_add_strn(dest, file_str, file_len);
|
||||
mp_import_stat_t stat = stat_dir_or_file(dest);
|
||||
if (stat != MP_IMPORT_STAT_NO_EXIST) {
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
|
||||
// could not find a directory or file
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
// could not find a directory or file
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
#endif
|
||||
|
||||
// mp_sys_path is empty (or not enabled), so just stat the given path
|
||||
// directly.
|
||||
vstr_add_str(dest, qstr_str(mod_name));
|
||||
return stat_dir_or_file(dest);
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER
|
||||
@ -193,19 +203,17 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co
|
||||
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
#if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)
|
||||
char *file_str = vstr_null_terminated_str(file);
|
||||
const char *file_str = vstr_null_terminated_str(file);
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN || MICROPY_MODULE_FROZEN_MPY
|
||||
if (strncmp(MP_FROZEN_FAKE_DIR_SLASH,
|
||||
file_str,
|
||||
MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
|
||||
// If we support frozen modules (either as str or mpy) then try to find the
|
||||
// requested filename in the list of frozen module filenames.
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
void *modref;
|
||||
int frozen_type = mp_find_frozen_module(file_str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH, file->len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH, &modref);
|
||||
#endif
|
||||
// If we support frozen modules (either as str or mpy) then try to find the
|
||||
// requested filename in the list of frozen module filenames.
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
void *modref;
|
||||
int frozen_type;
|
||||
const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
|
||||
if (strncmp(file_str, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
|
||||
mp_find_frozen_module(file_str + frozen_path_prefix_len, &frozen_type, &modref);
|
||||
|
||||
// If we support frozen str modules and the compiler is enabled, and we
|
||||
// found the filename in the list of frozen files, then load and execute it.
|
||||
@ -220,13 +228,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// its data) in the list of frozen files, execute it.
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
if (frozen_type == MP_FROZEN_MPY) {
|
||||
do_execute_raw_code(module_obj, modref, file_str);
|
||||
do_execute_raw_code(module_obj, modref, file_str + frozen_path_prefix_len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif // MICROPY_MODULE_FROZEN || MICROPY_MODULE_FROZEN_MPY
|
||||
#endif // MICROPY_MODULE_FROZEN
|
||||
|
||||
// If we support loading .mpy files then check if the file extension is of
|
||||
// the correct format and, if so, load and execute the file.
|
||||
@ -251,15 +258,212 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void chop_component(const char *start, const char **end) {
|
||||
const char *p = *end;
|
||||
while (p > start) {
|
||||
// Convert a relative (to the current module) import, going up "level" levels,
|
||||
// into an absolute import.
|
||||
STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) {
|
||||
// What we want to do here is to take the name of the current module,
|
||||
// remove <level> trailing components, and concatenate the passed-in
|
||||
// module name.
|
||||
// For example, level=3, module_name="foo.bar", __name__="a.b.c.d" --> "a.foo.bar"
|
||||
// "Relative imports use a module's __name__ attribute to determine that
|
||||
// module's position in the package hierarchy."
|
||||
// http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
|
||||
|
||||
mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
|
||||
assert(current_module_name_obj != MP_OBJ_NULL);
|
||||
|
||||
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT
|
||||
if (MP_OBJ_QSTR_VALUE(current_module_name_obj) == MP_QSTR___main__) {
|
||||
// This is a module loaded by -m command-line switch (e.g. unix port),
|
||||
// and so its __name__ has been set to "__main__". Get its real name
|
||||
// that we stored during import in the __main__ attribute.
|
||||
current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we have a __path__ in the globals dict, then we're a package.
|
||||
bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
|
||||
|
||||
#if DEBUG_PRINT
|
||||
DEBUG_printf("Current module/package: ");
|
||||
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, current_module_name_obj, PRINT_REPR);
|
||||
DEBUG_printf(", is_package: %d", is_pkg);
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
|
||||
size_t current_module_name_len;
|
||||
const char *current_module_name = mp_obj_str_get_data(current_module_name_obj, ¤t_module_name_len);
|
||||
|
||||
const char *p = current_module_name + current_module_name_len;
|
||||
if (is_pkg) {
|
||||
// If we're evaluating relative to a package, then take off one fewer
|
||||
// level (i.e. the relative search starts inside the package, rather
|
||||
// than as a sibling of the package).
|
||||
--level;
|
||||
}
|
||||
|
||||
// Walk back 'level' dots (or run out of path).
|
||||
while (level && p > current_module_name) {
|
||||
if (*--p == '.') {
|
||||
*end = p;
|
||||
return;
|
||||
--level;
|
||||
}
|
||||
}
|
||||
*end = p;
|
||||
|
||||
// We must have some component left over to import from.
|
||||
if (p == current_module_name) {
|
||||
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import"));
|
||||
}
|
||||
|
||||
// New length is len("<chopped path>.<module_name>"). Note: might be one byte
|
||||
// more than we need if module_name is empty (for the extra . we will
|
||||
// append).
|
||||
uint new_module_name_len = (size_t)(p - current_module_name) + 1 + *module_name_len;
|
||||
char *new_mod = mp_local_alloc(new_module_name_len);
|
||||
memcpy(new_mod, current_module_name, p - current_module_name);
|
||||
|
||||
// Only append ".<module_name>" if there was one).
|
||||
if (*module_name_len != 0) {
|
||||
new_mod[p - current_module_name] = '.';
|
||||
memcpy(new_mod + (p - current_module_name) + 1, *module_name, *module_name_len);
|
||||
} else {
|
||||
--new_module_name_len;
|
||||
}
|
||||
|
||||
// Copy into a QSTR.
|
||||
qstr new_mod_q = qstr_from_strn(new_mod, new_module_name_len);
|
||||
mp_local_free(new_mod);
|
||||
|
||||
DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
|
||||
*module_name = qstr_str(new_mod_q);
|
||||
*module_name_len = new_module_name_len;
|
||||
}
|
||||
|
||||
// Load a module at the specified absolute path, possibly as a submodule of the given outer module.
|
||||
// full_mod_name: The full absolute path to this module (e.g. "foo.bar.baz").
|
||||
// level_mod_name: The final component of the path (e.g. "baz").
|
||||
// outer_module_obj: The parent module (we need to store this module as an
|
||||
// attribute on it) (or MP_OBJ_NULL for top-level).
|
||||
// path: The filesystem path where we found the parent module
|
||||
// (or empty for a top level module).
|
||||
// override_main: Whether to set the __name__ to "__main__" (and use __main__
|
||||
// for the actual path).
|
||||
STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, mp_obj_t outer_module_obj, vstr_t *path, bool override_main) {
|
||||
mp_import_stat_t stat = MP_IMPORT_STAT_NO_EXIST;
|
||||
|
||||
// Exact-match of built-in (or already-loaded) takes priority.
|
||||
mp_obj_t module_obj = mp_module_get_loaded_or_builtin(full_mod_name);
|
||||
|
||||
// Even if we find the module, go through the motions of searching for it
|
||||
// because we may actually be in the process of importing a sub-module.
|
||||
// So we need to (re-)find the correct path to be finding the sub-module
|
||||
// on the next iteration of process_import_at_level.
|
||||
|
||||
if (outer_module_obj == MP_OBJ_NULL) {
|
||||
DEBUG_printf("Searching for top-level module\n");
|
||||
|
||||
// First module in the dotted-name; search for a directory or file
|
||||
// relative to all the locations in sys.path.
|
||||
stat = stat_top_level_dir_or_file(full_mod_name, path);
|
||||
|
||||
// If the module "foo" doesn't exist on the filesystem, and it's not a
|
||||
// builtin, try and find "ufoo" as a built-in. (This feature was
|
||||
// formerly known as "weak links").
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL) {
|
||||
char *umodule_buf = vstr_str(path);
|
||||
umodule_buf[0] = 'u';
|
||||
strcpy(umodule_buf + 1, qstr_str(level_mod_name));
|
||||
qstr umodule_name = qstr_from_str(umodule_buf);
|
||||
module_obj = mp_module_get_builtin(umodule_name);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_printf("Searching for sub-module\n");
|
||||
|
||||
// Add the current part of the module name to the path.
|
||||
vstr_add_char(path, PATH_SEP_CHAR[0]);
|
||||
vstr_add_str(path, qstr_str(level_mod_name));
|
||||
|
||||
// Because it's not top level, we already know which path the parent was found in.
|
||||
stat = stat_dir_or_file(path);
|
||||
}
|
||||
DEBUG_printf("Current path: %.*s\n", (int)vstr_len(path), vstr_str(path));
|
||||
|
||||
if (module_obj == MP_OBJ_NULL) {
|
||||
// Not a built-in and not already-loaded.
|
||||
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST) {
|
||||
// And the file wasn't found -- fail.
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Not a built-in but found on the filesystem, try and load it.
|
||||
|
||||
DEBUG_printf("Found path: %.*s\n", (int)vstr_len(path), vstr_str(path));
|
||||
|
||||
// Prepare for loading from the filesystem. Create a new shell module.
|
||||
module_obj = mp_obj_new_module(full_mod_name);
|
||||
|
||||
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
|
||||
// If this module is being loaded via -m on unix, then
|
||||
// override __name__ to "__main__". Do this only for *modules*
|
||||
// however - packages never have their names replaced, instead
|
||||
// they're -m'ed using a special __main__ submodule in them. (This all
|
||||
// apparently is done to not touch the package name itself, which is
|
||||
// important for future imports).
|
||||
if (override_main && stat != MP_IMPORT_STAT_DIR) {
|
||||
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
// Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
|
||||
// Store real name in "__main__" attribute. Need this for
|
||||
// resolving relative imports later. "__main__ was chosen
|
||||
// semi-randonly, to reuse existing qstr's.
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(full_mod_name));
|
||||
#endif
|
||||
}
|
||||
#endif // MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
// Directory -- execute "path/__init__.py".
|
||||
DEBUG_printf("%.*s is dir\n", (int)vstr_len(path), vstr_str(path));
|
||||
// Store the __path__ attribute onto this module.
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
// "Specifically, any module that contains a __path__ attribute is considered a package."
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(path), vstr_len(path)));
|
||||
size_t orig_path_len = path->len;
|
||||
vstr_add_str(path, PATH_SEP_CHAR "__init__.py");
|
||||
if (stat_file_py_or_mpy(path) == MP_IMPORT_STAT_FILE) {
|
||||
do_load(module_obj, path);
|
||||
} else {
|
||||
// No-op. Nothing to load.
|
||||
// mp_warning("%s is imported as namespace package", vstr_str(&path));
|
||||
}
|
||||
// Remove /__init__.py suffix.
|
||||
path->len = orig_path_len;
|
||||
} else { // MP_IMPORT_STAT_FILE
|
||||
// File -- execute "path.(m)py".
|
||||
do_load(module_obj, path);
|
||||
// Note: This should be the last component in the import path. If
|
||||
// there are remaining components then it's an ImportError
|
||||
// because the current path(the module that was just loaded) is
|
||||
// not a package. This will be caught on the next iteration
|
||||
// because the file will not exist.
|
||||
}
|
||||
}
|
||||
|
||||
if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(MP_OBJ_TO_PTR(outer_module_obj))) {
|
||||
// If it's a sub-module (not a built-in one), then make it available on
|
||||
// the parent module.
|
||||
mp_store_attr(outer_module_obj, level_mod_name, module_obj);
|
||||
}
|
||||
|
||||
return module_obj;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
@ -267,14 +471,28 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
DEBUG_printf("__import__:\n");
|
||||
for (size_t i = 0; i < n_args; i++) {
|
||||
DEBUG_printf(" ");
|
||||
mp_obj_print(args[i], PRINT_REPR);
|
||||
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, args[i], PRINT_REPR);
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t module_name = args[0];
|
||||
// This is the import path, with any leading dots stripped.
|
||||
// "import foo.bar" --> module_name="foo.bar"
|
||||
// "from foo.bar import baz" --> module_name="foo.bar"
|
||||
// "from . import foo" --> module_name=""
|
||||
// "from ...foo.bar import baz" --> module_name="foo.bar"
|
||||
mp_obj_t module_name_obj = args[0];
|
||||
|
||||
// These are the imported names.
|
||||
// i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",)
|
||||
// Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__.
|
||||
mp_obj_t fromtuple = mp_const_none;
|
||||
|
||||
// Level is the number of leading dots in a relative import.
|
||||
// i.e. "from . import foo" --> level=1
|
||||
// i.e. "from ...foo.bar import baz" --> level=3
|
||||
mp_int_t level = 0;
|
||||
|
||||
if (n_args >= 4) {
|
||||
fromtuple = args[3];
|
||||
if (n_args >= 5) {
|
||||
@ -285,226 +503,64 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t mod_len;
|
||||
const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);
|
||||
size_t module_name_len;
|
||||
const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len);
|
||||
|
||||
if (level != 0) {
|
||||
// What we want to do here is to take name of current module,
|
||||
// chop <level> trailing components, and concatenate with passed-in
|
||||
// module name, thus resolving relative import name into absolute.
|
||||
// This even appears to be correct per
|
||||
// http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
|
||||
// "Relative imports use a module's __name__ attribute to determine that
|
||||
// module's position in the package hierarchy."
|
||||
level--;
|
||||
mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
|
||||
assert(this_name_q != MP_OBJ_NULL);
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) {
|
||||
// This is a module run by -m command-line switch, get its real name from backup attribute
|
||||
this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
}
|
||||
#endif
|
||||
mp_map_t *globals_map = &mp_globals_get()->map;
|
||||
mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
|
||||
bool is_pkg = (elem != NULL);
|
||||
|
||||
#if DEBUG_PRINT
|
||||
DEBUG_printf("Current module/package: ");
|
||||
mp_obj_print(this_name_q, PRINT_REPR);
|
||||
DEBUG_printf(", is_package: %d", is_pkg);
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
|
||||
size_t this_name_l;
|
||||
const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);
|
||||
|
||||
const char *p = this_name + this_name_l;
|
||||
if (!is_pkg) {
|
||||
// We have module, but relative imports are anchored at package, so
|
||||
// go there.
|
||||
chop_component(this_name, &p);
|
||||
}
|
||||
|
||||
while (level--) {
|
||||
chop_component(this_name, &p);
|
||||
}
|
||||
|
||||
// We must have some component left over to import from
|
||||
if (p == this_name) {
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("cannot perform relative import"));
|
||||
}
|
||||
|
||||
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
|
||||
char *new_mod = mp_local_alloc(new_mod_l);
|
||||
memcpy(new_mod, this_name, p - this_name);
|
||||
if (mod_len != 0) {
|
||||
new_mod[p - this_name] = '.';
|
||||
memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len);
|
||||
}
|
||||
|
||||
qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);
|
||||
mp_local_free(new_mod);
|
||||
DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
|
||||
module_name = MP_OBJ_NEW_QSTR(new_mod_q);
|
||||
mod_str = qstr_str(new_mod_q);
|
||||
mod_len = new_mod_l;
|
||||
// Turn "foo.bar" into "<current module minus 3 components>.foo.bar".
|
||||
evaluate_relative_import(level, &module_name, &module_name_len);
|
||||
}
|
||||
|
||||
if (mod_len == 0) {
|
||||
if (module_name_len == 0) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
// check if module already exists
|
||||
qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
|
||||
mp_obj_t module_obj = mp_module_get(module_name_qstr);
|
||||
if (module_obj != MP_OBJ_NULL) {
|
||||
DEBUG_printf("Module already loaded\n");
|
||||
// If it's not a package, return module right away
|
||||
char *p = strchr(mod_str, '.');
|
||||
if (p == NULL) {
|
||||
return module_obj;
|
||||
}
|
||||
// If fromlist is not empty, return leaf module
|
||||
if (fromtuple != mp_const_none) {
|
||||
return module_obj;
|
||||
}
|
||||
// Otherwise, we need to return top-level package
|
||||
qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
|
||||
return mp_module_get(pkg_name);
|
||||
}
|
||||
DEBUG_printf("Module not yet loaded\n");
|
||||
DEBUG_printf("Starting module search for '%s'\n", module_name);
|
||||
|
||||
uint last = 0;
|
||||
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
|
||||
module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t top_module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t outer_module_obj = MP_OBJ_NULL;
|
||||
uint i;
|
||||
for (i = 1; i <= mod_len; i++) {
|
||||
if (i == mod_len || mod_str[i] == '.') {
|
||||
// create a qstr for the module name up to this depth
|
||||
qstr mod_name = qstr_from_strn(mod_str, i);
|
||||
DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
|
||||
DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path));
|
||||
|
||||
// find the file corresponding to the module name
|
||||
mp_import_stat_t stat;
|
||||
if (vstr_len(&path) == 0) {
|
||||
// first module in the dotted-name; search for a directory or file
|
||||
DEBUG_printf("Find file =%.*s=\n", vstr_len(&path), vstr_str(&path));
|
||||
stat = find_file(mod_str, i, &path);
|
||||
} else {
|
||||
// latter module in the dotted-name; append to path
|
||||
vstr_add_char(&path, PATH_SEP_CHAR);
|
||||
vstr_add_strn(&path, mod_str + last, i - last);
|
||||
stat = stat_dir_or_file(&path);
|
||||
}
|
||||
DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));
|
||||
// Search for the end of each component.
|
||||
size_t current_component_start = 0;
|
||||
for (size_t i = 1; i <= module_name_len; i++) {
|
||||
if (i == module_name_len || module_name[i] == '.') {
|
||||
// The module name up to this depth (e.g. foo.bar.baz).
|
||||
qstr full_mod_name = qstr_from_strn(module_name, i);
|
||||
// The current level name (e.g. baz).
|
||||
qstr level_mod_name = qstr_from_strn(module_name + current_component_start, i - current_component_start);
|
||||
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST) {
|
||||
// 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);
|
||||
} else {
|
||||
el = mp_map_lookup(&((mp_obj_module_t *)outer_module_obj)->globals->map,
|
||||
MP_OBJ_NEW_QSTR(current_module_name),
|
||||
MP_MAP_LOOKUP);
|
||||
}
|
||||
DEBUG_printf("Processing module: '%s' at level '%s'\n", qstr_str(full_mod_name), qstr_str(level_mod_name));
|
||||
DEBUG_printf("Previous path: =%.*s=\n", (int)vstr_len(&path), vstr_str(&path));
|
||||
|
||||
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 {
|
||||
// couldn't find the file, so fail
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError,
|
||||
MP_ERROR_TEXT("no module named '%q'"), mod_name);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
// found the file, so get the module
|
||||
module_obj = mp_module_get(mod_name);
|
||||
}
|
||||
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
|
||||
// On unix, if this is being loaded via -m (magic mp_const_false),
|
||||
// then handle that if it's the final component.
|
||||
bool override_main = (i == module_name_len && fromtuple == mp_const_false);
|
||||
#else
|
||||
bool override_main = false;
|
||||
#endif
|
||||
|
||||
if (module_obj == MP_OBJ_NULL) {
|
||||
// module not already loaded, so load it!
|
||||
// Import this module.
|
||||
mp_obj_t module_obj = process_import_at_level(full_mod_name, level_mod_name, outer_module_obj, &path, override_main);
|
||||
|
||||
module_obj = mp_obj_new_module(mod_name);
|
||||
|
||||
// if args[3] (fromtuple) has magic value False, set up
|
||||
// this module for command-line "-m" option (set module's
|
||||
// name to __main__ instead of real name). Do this only
|
||||
// for *modules* however - packages never have their names
|
||||
// replaced, instead they're -m'ed using a special __main__
|
||||
// submodule in them. (This all apparently is done to not
|
||||
// touch package name itself, which is important for future
|
||||
// imports).
|
||||
if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) {
|
||||
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
// Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
|
||||
// Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's.
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path));
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
// "Specifically, any module that contains a __path__ attribute is considered a package."
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
|
||||
size_t orig_path_len = path.len;
|
||||
vstr_add_char(&path, PATH_SEP_CHAR);
|
||||
vstr_add_str(&path, "__init__.py");
|
||||
if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) {
|
||||
// mp_warning("%s is imported as namespace package", vstr_str(&path));
|
||||
} else {
|
||||
do_load(module_obj, &path);
|
||||
}
|
||||
path.len = orig_path_len;
|
||||
} else { // MP_IMPORT_STAT_FILE
|
||||
do_load(module_obj, &path);
|
||||
// This should be the last component in the import path. If there are
|
||||
// remaining components then it's an ImportError because the current path
|
||||
// (the module that was just loaded) is not a package. This will be caught
|
||||
// on the next iteration because the file will not exist.
|
||||
}
|
||||
|
||||
// Loading a module thrashes the heap significantly so we explicitly clean up
|
||||
// afterwards.
|
||||
gc_collect();
|
||||
}
|
||||
if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(MP_OBJ_TO_PTR(outer_module_obj))) {
|
||||
qstr s = qstr_from_strn(mod_str + last, i - last);
|
||||
mp_store_attr(outer_module_obj, s, module_obj);
|
||||
// The above store can cause a dictionary rehash and new allocation. So,
|
||||
// lets make sure the globals dictionary is still long lived.
|
||||
mp_obj_module_set_globals(outer_module_obj,
|
||||
make_dict_long_lived(mp_obj_module_get_globals(outer_module_obj), 10));
|
||||
}
|
||||
// Set this as the parent module, and remember the top-level module if it's the first.
|
||||
outer_module_obj = module_obj;
|
||||
if (top_module_obj == MP_OBJ_NULL) {
|
||||
top_module_obj = module_obj;
|
||||
}
|
||||
last = i + 1;
|
||||
|
||||
current_component_start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If fromlist is not empty, return leaf module
|
||||
if (fromtuple != mp_const_none) {
|
||||
return module_obj;
|
||||
// If fromtuple is not empty, return leaf module
|
||||
return outer_module_obj;
|
||||
} else {
|
||||
// Otherwise, we need to return top-level package
|
||||
return top_module_obj;
|
||||
}
|
||||
// Otherwise, we need to return top-level package
|
||||
return top_module_obj;
|
||||
}
|
||||
|
||||
#else // MICROPY_ENABLE_EXTERNAL_IMPORT
|
||||
@ -517,17 +573,19 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
// Check if module already exists, and return it if it does
|
||||
qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);
|
||||
mp_obj_t module_obj = mp_module_get(module_name_qstr);
|
||||
mp_obj_t module_obj = mp_module_get_loaded_or_builtin(module_name_qstr);
|
||||
if (module_obj != MP_OBJ_NULL) {
|
||||
return module_obj;
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
// Check if there is a weak link to this module
|
||||
module_obj = mp_module_search_umodule(qstr_str(module_name_qstr));
|
||||
char umodule_buf[MICROPY_ALLOC_PATH_MAX];
|
||||
umodule_buf[0] = 'u';
|
||||
strcpy(umodule_buf + 1, args[0]);
|
||||
qstr umodule_name_qstr = qstr_from_str(umodule_buf);
|
||||
module_obj = mp_module_get_loaded_or_builtin(umodule_name_qstr);
|
||||
if (module_obj != MP_OBJ_NULL) {
|
||||
// Found weak-linked module
|
||||
mp_module_call_init(module_name_qstr, module_obj);
|
||||
return module_obj;
|
||||
}
|
||||
#endif
|
||||
|
@ -87,6 +87,7 @@ extern void common_hal_mcu_enable_interrupts(void);
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (1)
|
||||
#define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE)
|
||||
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
|
||||
#define MICROPY_OPT_MAP_LOOKUP_CACHE (CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
|
||||
#define MICROPY_PERSISTENT_CODE_LOAD (1)
|
||||
|
||||
@ -541,5 +542,16 @@ void supervisor_run_background_tasks_if_tick(void);
|
||||
#define USB_MIDI_EP_NUM_IN (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_MAP_LOOKUP
|
||||
#define MICROPY_WRAP_MP_MAP_LOOKUP PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_BINARY_OP
|
||||
#define MICROPY_WRAP_MP_BINARY_OP PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE
|
||||
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H
|
||||
|
@ -162,13 +162,8 @@ CFLAGS += -DCIRCUITPY_COMPUTED_GOTO_SAVE_SPACE=$(CIRCUITPY_COMPUTED_GOTO_SAVE_SP
|
||||
CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH ?= 1
|
||||
CFLAGS += -DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=$(CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
|
||||
|
||||
# This is disabled because it changes the bytecode format. We could choose to enable it
|
||||
# when we go to 8.x, but probably not for 7.1.
|
||||
CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ?= 0
|
||||
CFLAGS += -DCIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=$(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
|
||||
ifeq ($(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE),1)
|
||||
MPY_CROSS_FLAGS += -mcache-lookup-bc
|
||||
endif
|
||||
CIRCUITPY_OPT_MAP_LOOKUP_CACHE ?= $(CIRCUITPY_FULL_BUILD)
|
||||
CFLAGS += -DCIRCUITPY_OPT_MAP_LOOKUP_CACHE=$(CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
|
||||
|
||||
CIRCUITPY_CONSOLE_UART ?= 0
|
||||
CFLAGS += -DCIRCUITPY_CONSOLE_UART=$(CIRCUITPY_CONSOLE_UART)
|
||||
@ -489,6 +484,7 @@ CFLAGS += -DLONGINT_IMPL_LONGLONG
|
||||
else
|
||||
$(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
|
||||
endif
|
||||
MPY_TOOL_FLAGS += $(MPY_TOOL_LONGINT_IMPL)
|
||||
|
||||
###
|
||||
ifeq ($(LONGINT_IMPL),NONE)
|
||||
@ -497,3 +493,16 @@ else ifeq ($(LONGINT_IMPL),LONGLONG)
|
||||
else
|
||||
$(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
|
||||
endif
|
||||
|
||||
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
|
||||
ifneq ($(FROZEN_MPY_DIRS),)
|
||||
$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
|
||||
$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
|
||||
$(Q)$(MKDIR) -p $@
|
||||
$(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
|
||||
|
||||
$(BUILD)/manifest.py: $(BUILD)/frozen_mpy | $(TOP)/py/circuitpy_mpconfig.mk mpconfigport.mk boards/$(BOARD)/mpconfigboard.mk
|
||||
$(ECHO) MKMANIFEST $(FROZEN_MPY_DIRS)
|
||||
(cd $(BUILD)/frozen_mpy && find * -name \*.py -exec printf 'freeze_as_mpy("frozen_mpy", "%s")\n' {} \; )> $@.tmp && mv -f $@.tmp $@
|
||||
FROZEN_MANIFEST=$(BUILD)/manifest.py
|
||||
endif
|
||||
|
169
py/compile.c
169
py/compile.c
@ -61,6 +61,12 @@ typedef enum {
|
||||
#undef DEF_RULE_NC
|
||||
} pn_kind_t;
|
||||
|
||||
// Whether a mp_parse_node_struct_t that has pns->kind == PN_testlist_comp
|
||||
// corresponds to a list comprehension or generator.
|
||||
#define MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns) \
|
||||
(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2 && \
|
||||
MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for))
|
||||
|
||||
#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
|
||||
|
||||
#if NEED_METHOD_TABLE
|
||||
@ -319,25 +325,13 @@ STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
|
||||
int total = 0;
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
compile_node(comp, pn);
|
||||
total += 1;
|
||||
}
|
||||
if (pns_list != NULL) {
|
||||
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
|
||||
for (int i = 0; i < n; i++) {
|
||||
compile_node(comp, pns_list->nodes[i]);
|
||||
}
|
||||
total += n;
|
||||
}
|
||||
EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE);
|
||||
}
|
||||
|
||||
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// a simple tuple expression
|
||||
c_tuple(comp, MP_PARSE_NODE_NULL, pns);
|
||||
size_t num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
for (size_t i = 0; i < num_nodes; i++) {
|
||||
compile_node(comp, pns->nodes[i]);
|
||||
}
|
||||
EMIT_ARG(build, num_nodes, MP_EMIT_BUILD_TUPLE);
|
||||
}
|
||||
|
||||
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
|
||||
@ -454,21 +448,14 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("can't assign to expression"));
|
||||
}
|
||||
|
||||
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
|
||||
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
|
||||
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
|
||||
|
||||
STATIC void c_assign_tuple(compiler_t *comp, uint num_tail, mp_parse_node_t *nodes_tail) {
|
||||
// look for star expression
|
||||
uint have_star_index = -1;
|
||||
if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
|
||||
EMIT_ARG(unpack_ex, 0, num_tail);
|
||||
have_star_index = 0;
|
||||
}
|
||||
for (uint i = 0; i < num_tail; i++) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
|
||||
if (have_star_index == (uint)-1) {
|
||||
EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
|
||||
have_star_index = num_head + i;
|
||||
EMIT_ARG(unpack_ex, i, num_tail - i - 1);
|
||||
have_star_index = i;
|
||||
} else {
|
||||
compile_syntax_error(comp, nodes_tail[i], MP_ERROR_TEXT("multiple *x in assignment"));
|
||||
return;
|
||||
@ -476,17 +463,10 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
|
||||
}
|
||||
}
|
||||
if (have_star_index == (uint)-1) {
|
||||
EMIT_ARG(unpack_sequence, num_head + num_tail);
|
||||
}
|
||||
if (num_head != 0) {
|
||||
if (0 == have_star_index) {
|
||||
c_assign(comp, ((mp_parse_node_struct_t *)node_head)->nodes[0], ASSIGN_STORE);
|
||||
} else {
|
||||
c_assign(comp, node_head, ASSIGN_STORE);
|
||||
}
|
||||
EMIT_ARG(unpack_sequence, num_tail);
|
||||
}
|
||||
for (uint i = 0; i < num_tail; i++) {
|
||||
if (num_head + i == have_star_index) {
|
||||
if (i == have_star_index) {
|
||||
c_assign(comp, ((mp_parse_node_struct_t *)nodes_tail[i])->nodes[0], ASSIGN_STORE);
|
||||
} else {
|
||||
c_assign(comp, nodes_tail[i], ASSIGN_STORE);
|
||||
@ -528,7 +508,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
if (assign_kind != ASSIGN_STORE) {
|
||||
goto cannot_assign;
|
||||
}
|
||||
c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
|
||||
c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
|
||||
break;
|
||||
|
||||
case PN_atom_paren:
|
||||
@ -553,13 +533,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
||||
// empty list, assignment allowed
|
||||
c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
|
||||
c_assign_tuple(comp, 0, NULL);
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
|
||||
pns = (mp_parse_node_struct_t *)pns->nodes[0];
|
||||
goto testlist_comp;
|
||||
} else {
|
||||
// brackets around 1 item
|
||||
c_assign_tuple(comp, pns->nodes[0], 0, NULL);
|
||||
c_assign_tuple(comp, 1, pns->nodes);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -570,27 +550,10 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
|
||||
testlist_comp:
|
||||
// lhs is a sequence
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
|
||||
// sequence of one item, with trailing comma
|
||||
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
|
||||
c_assign_tuple(comp, pns->nodes[0], 0, NULL);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
|
||||
// sequence of many items
|
||||
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
|
||||
c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
|
||||
goto cannot_assign;
|
||||
} else {
|
||||
// sequence with 2 items
|
||||
goto sequence_with_2_items;
|
||||
}
|
||||
} else {
|
||||
// sequence with 2 items
|
||||
sequence_with_2_items:
|
||||
c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
|
||||
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
|
||||
goto cannot_assign;
|
||||
}
|
||||
c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
@ -993,32 +956,11 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
|
||||
// TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp
|
||||
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) {
|
||||
// sequence of one item, with trailing comma
|
||||
assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));
|
||||
c_del_stmt(comp, pns->nodes[0]);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {
|
||||
// sequence of many items
|
||||
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
|
||||
c_del_stmt(comp, pns->nodes[0]);
|
||||
for (int i = 0; i < n; i++) {
|
||||
c_del_stmt(comp, pns1->nodes[i]);
|
||||
}
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {
|
||||
goto cannot_delete;
|
||||
} else {
|
||||
// sequence with 2 items
|
||||
goto sequence_with_2_items;
|
||||
}
|
||||
} else {
|
||||
// sequence with 2 items
|
||||
sequence_with_2_items:
|
||||
c_del_stmt(comp, pns->nodes[0]);
|
||||
c_del_stmt(comp, pns->nodes[1]);
|
||||
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
|
||||
goto cannot_delete;
|
||||
}
|
||||
for (size_t i = 0; i < MP_PARSE_NODE_STRUCT_NUM_NODES(pns); ++i) {
|
||||
c_del_stmt(comp, pns->nodes[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2502,31 +2444,16 @@ STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns,
|
||||
STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
||||
// an empty tuple
|
||||
c_tuple(comp, MP_PARSE_NODE_NULL, NULL);
|
||||
EMIT_ARG(build, 0, MP_EMIT_BUILD_TUPLE);
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
|
||||
pns = (mp_parse_node_struct_t *)pns->nodes[0];
|
||||
assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1]));
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
|
||||
// tuple of one item, with trailing comma
|
||||
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
|
||||
c_tuple(comp, pns->nodes[0], NULL);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
|
||||
// tuple of many items
|
||||
c_tuple(comp, pns->nodes[0], pns2);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
|
||||
// generator expression
|
||||
compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
|
||||
} else {
|
||||
// tuple with 2 items
|
||||
goto tuple_with_2_items;
|
||||
}
|
||||
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
|
||||
// generator expression
|
||||
compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
|
||||
} else {
|
||||
// tuple with 2 items
|
||||
tuple_with_2_items:
|
||||
c_tuple(comp, MP_PARSE_NODE_NULL, pns);
|
||||
// tuple with N items
|
||||
compile_generic_tuple(comp, pns);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2537,31 +2464,13 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
|
||||
EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
|
||||
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[0];
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns2->nodes[1];
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) {
|
||||
// list of one item, with trailing comma
|
||||
assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0]));
|
||||
compile_node(comp, pns2->nodes[0]);
|
||||
EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) {
|
||||
// list of many items
|
||||
compile_node(comp, pns2->nodes[0]);
|
||||
compile_generic_all_nodes(comp, pns3);
|
||||
EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST);
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) {
|
||||
// list comprehension
|
||||
compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
|
||||
} else {
|
||||
// list with 2 items
|
||||
goto list_with_2_items;
|
||||
}
|
||||
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns2)) {
|
||||
// list comprehension
|
||||
compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
|
||||
} else {
|
||||
// list with 2 items
|
||||
list_with_2_items:
|
||||
compile_node(comp, pns2->nodes[0]);
|
||||
compile_node(comp, pns2->nodes[1]);
|
||||
EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST);
|
||||
// list with N items
|
||||
compile_generic_all_nodes(comp, pns2);
|
||||
EMIT_ARG(build, MP_PARSE_NODE_STRUCT_NUM_NODES(pns2), MP_EMIT_BUILD_LIST);
|
||||
}
|
||||
} else {
|
||||
// list with 1 item
|
||||
|
@ -46,7 +46,6 @@ ifeq ($(ARCH),x86)
|
||||
# x86
|
||||
CROSS =
|
||||
CFLAGS += -m32 -fno-stack-protector
|
||||
MPY_CROSS_FLAGS += -mcache-lookup-bc
|
||||
MICROPY_FLOAT_IMPL ?= double
|
||||
|
||||
else ifeq ($(ARCH),x64)
|
||||
@ -54,7 +53,6 @@ else ifeq ($(ARCH),x64)
|
||||
# x64
|
||||
CROSS =
|
||||
CFLAGS += -fno-stack-protector
|
||||
MPY_CROSS_FLAGS += -mcache-lookup-bc
|
||||
MICROPY_FLOAT_IMPL ?= double
|
||||
|
||||
else ifeq ($(ARCH),armv7m)
|
||||
|
@ -560,9 +560,6 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {
|
||||
MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);
|
||||
(void)qst;
|
||||
emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
|
||||
emit_write_bytecode_raw_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
|
||||
@ -596,9 +593,6 @@ void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {
|
||||
}
|
||||
emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst);
|
||||
}
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
|
||||
emit_write_bytecode_raw_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
|
||||
|
@ -1588,6 +1588,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
|
||||
int reg_base = REG_ARG_1;
|
||||
int reg_index = REG_ARG_2;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_index);
|
||||
need_reg_single(emit, REG_RET, 0);
|
||||
switch (vtype_base) {
|
||||
case VTYPE_PTR8: {
|
||||
// pointer to 8-bit memory
|
||||
@ -1651,6 +1652,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
|
||||
int reg_index = REG_ARG_2;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, REG_ARG_1);
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
|
||||
need_reg_single(emit, REG_RET, 0);
|
||||
if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
|
||||
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
|
||||
MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index));
|
||||
|
176
py/frozenmod.c
176
py/frozenmod.c
@ -5,6 +5,7 @@
|
||||
*
|
||||
* Copyright (c) 2015 Paul Sokolovsky
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jim Mussared
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -31,6 +32,13 @@
|
||||
#include "py/lexer.h"
|
||||
#include "py/frozenmod.h"
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
|
||||
// Null-separated frozen file names. All string-type entries are listed first,
|
||||
// followed by mpy-type entries. Use mp_frozen_str_sizes to determine how
|
||||
// many string entries.
|
||||
extern const char mp_frozen_names[];
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
|
||||
#ifndef MICROPY_MODULE_FROZEN_LEXER
|
||||
@ -39,129 +47,89 @@
|
||||
mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
|
||||
#endif
|
||||
|
||||
extern const char mp_frozen_str_names[];
|
||||
// Size in bytes of each string entry, followed by a zero (terminator).
|
||||
extern const uint32_t mp_frozen_str_sizes[];
|
||||
// Null-separated string content.
|
||||
extern const char mp_frozen_str_content[];
|
||||
|
||||
// str_len is length of str. *len is set on on output to size of content
|
||||
const char *mp_find_frozen_str(const char *str, size_t str_len, size_t *len) {
|
||||
// If the frozen module pseudo dir (e.g., ".frozen/") is a prefix of str, remove it.
|
||||
if (strncmp(str, MP_FROZEN_FAKE_DIR_SLASH, MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
|
||||
str = str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
|
||||
str_len = str_len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
|
||||
}
|
||||
|
||||
const char *name = mp_frozen_str_names;
|
||||
|
||||
size_t offset = 0;
|
||||
for (int i = 0; *name != 0; i++) {
|
||||
size_t l = strlen(name);
|
||||
if (l == str_len && !memcmp(str, name, l)) {
|
||||
*len = mp_frozen_str_sizes[i];
|
||||
return mp_frozen_str_content + offset;
|
||||
}
|
||||
name += l + 1;
|
||||
offset += mp_frozen_str_sizes[i] + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t str_len) {
|
||||
size_t file_len;
|
||||
const char *content = mp_find_frozen_str(str, str_len, &file_len);
|
||||
|
||||
if (content == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qstr source = qstr_from_strn(str, str_len);
|
||||
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, file_len, 0);
|
||||
return lex;
|
||||
}
|
||||
#endif
|
||||
#endif // MICROPY_MODULE_FROZEN_STR
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
|
||||
#include "py/emitglue.h"
|
||||
|
||||
extern const char mp_frozen_mpy_names[];
|
||||
extern const mp_raw_code_t *const mp_frozen_mpy_content[];
|
||||
|
||||
STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t str_len) {
|
||||
const char *name = mp_frozen_mpy_names;
|
||||
for (size_t i = 0; *name != 0; i++) {
|
||||
size_t l = strlen(name);
|
||||
if (l == str_len && !memcmp(str, name, l)) {
|
||||
return mp_frozen_mpy_content[i];
|
||||
}
|
||||
name += l + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif // MICROPY_MODULE_FROZEN_MPY
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
|
||||
STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) {
|
||||
// Search for "str" as a frozen entry, returning the stat result
|
||||
// (no-exist/file/dir), as well as the type (none/str/mpy) and data.
|
||||
// frozen_type can be NULL if its value isn't needed (and then data is assumed to be NULL).
|
||||
mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data) {
|
||||
size_t len = strlen(str);
|
||||
const char *name = mp_frozen_names;
|
||||
|
||||
if (frozen_type != NULL) {
|
||||
*frozen_type = MP_FROZEN_NONE;
|
||||
}
|
||||
|
||||
// Count the number of str lengths we have to find how many str entries.
|
||||
size_t num_str = 0;
|
||||
#if MICROPY_MODULE_FROZEN_STR && MICROPY_MODULE_FROZEN_MPY
|
||||
for (const uint32_t *s = mp_frozen_str_sizes; *s != 0; ++s) {
|
||||
++num_str;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; *name != 0; i++) {
|
||||
size_t entry_len = strlen(name);
|
||||
if (entry_len >= len && memcmp(str, name, len) == 0) {
|
||||
// Query is a prefix of the current entry.
|
||||
if (entry_len == len) {
|
||||
// Exact match --> file.
|
||||
|
||||
if (frozen_type != NULL) {
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
if (i < num_str) {
|
||||
*frozen_type = MP_FROZEN_STR;
|
||||
// Use the size table to figure out where this index starts.
|
||||
size_t offset = 0;
|
||||
for (size_t j = 0; j < i; ++j) {
|
||||
offset += mp_frozen_str_sizes[j] + 1;
|
||||
}
|
||||
size_t content_len = mp_frozen_str_sizes[i];
|
||||
const char *content = &mp_frozen_str_content[offset];
|
||||
|
||||
// Note: str & len have been updated by find_frozen_entry to strip
|
||||
// the ".frozen/" prefix (to avoid this being a distinct qstr to
|
||||
// the original path QSTR in frozen_content.c).
|
||||
qstr source = qstr_from_strn(str, len);
|
||||
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, content_len, 0);
|
||||
*data = lex;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
if (i >= num_str) {
|
||||
*frozen_type = MP_FROZEN_MPY;
|
||||
// Load the corresponding index as a raw_code, taking
|
||||
// into account any string entries to offset by.
|
||||
*data = (void *)mp_frozen_mpy_content[i - num_str];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; *name != 0; i++) {
|
||||
size_t l = strlen(name);
|
||||
if (l >= len && !memcmp(str, name, len)) {
|
||||
if (name[len] == 0) {
|
||||
return MP_IMPORT_STAT_FILE;
|
||||
} else if (name[len] == '/') {
|
||||
// Matches up to directory separator, this is a valid
|
||||
// directory path.
|
||||
return MP_IMPORT_STAT_DIR;
|
||||
}
|
||||
}
|
||||
name += l + 1;
|
||||
// Skip null separator.
|
||||
name += entry_len + 1;
|
||||
}
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_import_stat_t mp_frozen_stat(const char *str) {
|
||||
mp_import_stat_t stat;
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
stat = mp_frozen_stat_helper(mp_frozen_str_names, str);
|
||||
if (stat != MP_IMPORT_STAT_NO_EXIST) {
|
||||
return stat;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str);
|
||||
if (stat != MP_IMPORT_STAT_NO_EXIST) {
|
||||
return stat;
|
||||
}
|
||||
#endif
|
||||
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
int mp_find_frozen_module(const char *str, size_t len, void **data) {
|
||||
// If the frozen module pseudo dir (e.g., ".frozen/") is a prefix of str, remove it.
|
||||
if (strncmp(str, MP_FROZEN_FAKE_DIR_SLASH, MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
|
||||
str = str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
|
||||
len = len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
mp_lexer_t *lex = mp_lexer_frozen_str(str, len);
|
||||
if (lex != NULL) {
|
||||
*data = lex;
|
||||
return MP_FROZEN_STR;
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);
|
||||
if (rc != NULL) {
|
||||
*data = (void *)rc;
|
||||
return MP_FROZEN_MPY;
|
||||
}
|
||||
#endif
|
||||
return MP_FROZEN_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // MICROPY_MODULE_FROZEN
|
||||
|
@ -35,18 +35,6 @@ enum {
|
||||
MP_FROZEN_MPY,
|
||||
};
|
||||
|
||||
// Frozen modules are in a pseudo-directory, so sys.path can control how they're found.
|
||||
#define MP_FROZEN_FAKE_DIR ".frozen"
|
||||
#define MP_FROZEN_FAKE_DIR_LENGTH (sizeof(MP_FROZEN_FAKE_DIR) - 1)
|
||||
|
||||
#define MP_FROZEN_FAKE_DIR_SLASH (MP_FROZEN_FAKE_DIR "/")
|
||||
#define MP_FROZEN_FAKE_DIR_SLASH_LENGTH (sizeof(MP_FROZEN_FAKE_DIR_SLASH) - 1)
|
||||
|
||||
// This should match MP_FROZEN_FAKE_DIR.
|
||||
#define MP_FROZEN_FAKE_DIR_QSTR MP_QSTR__dot_frozen
|
||||
|
||||
int mp_find_frozen_module(const char *str, size_t len, void **data);
|
||||
const char *mp_find_frozen_str(const char *str, size_t str_len, size_t *len);
|
||||
mp_import_stat_t mp_frozen_stat(const char *str);
|
||||
mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data);
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_FROZENMOD_H
|
||||
|
5
py/gc.c
5
py/gc.c
@ -238,6 +238,7 @@ STATIC void gc_mark_subtree(size_t block) {
|
||||
// Start with the block passed in the argument.
|
||||
size_t sp = 0;
|
||||
for (;;) {
|
||||
MICROPY_GC_HOOK_LOOP
|
||||
// work out number of consecutive blocks in the chain starting with this one
|
||||
size_t n_blocks = 0;
|
||||
do {
|
||||
@ -247,6 +248,7 @@ STATIC void gc_mark_subtree(size_t block) {
|
||||
// check this block's children
|
||||
void **ptrs = (void **)PTR_FROM_BLOCK(block);
|
||||
for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {
|
||||
MICROPY_GC_HOOK_LOOP
|
||||
void *ptr = *ptrs;
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
// Mark and push this pointer
|
||||
@ -280,6 +282,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
|
||||
// scan entire memory looking for blocks which have been marked but not their children
|
||||
for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
|
||||
MICROPY_GC_HOOK_LOOP
|
||||
// trace (again) if mark bit set
|
||||
if (ATB_GET_KIND(block) == AT_MARK) {
|
||||
gc_mark_subtree(block);
|
||||
@ -295,6 +298,7 @@ STATIC void gc_sweep(void) {
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
|
||||
MICROPY_GC_HOOK_LOOP
|
||||
switch (ATB_GET_KIND(block)) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@ -407,6 +411,7 @@ static void *gc_get_ptr(void **ptrs, int i) {
|
||||
|
||||
void gc_collect_root(void **ptrs, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
MICROPY_GC_HOOK_LOOP
|
||||
void *ptr = gc_get_ptr(ptrs, i);
|
||||
gc_mark(ptr);
|
||||
}
|
||||
|
11
py/lexer.c
11
py/lexer.c
@ -365,9 +365,16 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring)
|
||||
// (MicroPython limitation) note: this is completely unaware of
|
||||
// Python syntax and will not handle any expression containing '}' or ':'.
|
||||
// e.g. f'{"}"}' or f'{foo({})}'.
|
||||
while (!is_end(lex) && !is_char_or(lex, ':', '}')) {
|
||||
unsigned int nested_bracket_level = 0;
|
||||
while (!is_end(lex) && (nested_bracket_level != 0 || !is_char_or(lex, ':', '}'))) {
|
||||
unichar c = CUR_CHAR(lex);
|
||||
if (c == '[' || c == '{') {
|
||||
nested_bracket_level += 1;
|
||||
} else if (c == ']' || c == '}') {
|
||||
nested_bracket_level -= 1;
|
||||
}
|
||||
// like the default case at the end of this function, stay 8-bit clean
|
||||
vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex));
|
||||
vstr_add_byte(&lex->fstring_args, c);
|
||||
next_char(lex);
|
||||
}
|
||||
if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') {
|
||||
|
37
py/map.c
37
py/map.c
@ -42,6 +42,27 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#if MICROPY_OPT_MAP_LOOKUP_CACHE
|
||||
// MP_STATE_VM(map_lookup_cache) provides a cache of index to the last known
|
||||
// position of that index in any map. On a cache hit, this allows
|
||||
// short-circuiting the full linear search in the case of an ordered map
|
||||
// (i.e. all builtin modules and objects' locals dicts), and computation of
|
||||
// the hash (and potentially some linear probing) in the case of a regular
|
||||
// map. Note the same cache is shared across all maps.
|
||||
|
||||
// Gets the index into the cache for this index. Shift down by two to remove
|
||||
// mp_obj_t tag bits.
|
||||
#define MAP_CACHE_OFFSET(index) ((((uintptr_t)(index)) >> 2) % MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE)
|
||||
// Gets the map cache entry for the corresponding index.
|
||||
#define MAP_CACHE_ENTRY(index) (MP_STATE_VM(map_lookup_cache)[MAP_CACHE_OFFSET(index)])
|
||||
// Retrieve the mp_obj_t at the location suggested by the cache.
|
||||
#define MAP_CACHE_GET(map, index) (&(map)->table[MAP_CACHE_ENTRY(index) % (map)->alloc])
|
||||
// Update the cache for this index.
|
||||
#define MAP_CACHE_SET(index, pos) MAP_CACHE_ENTRY(index) = (pos) & 0xff;
|
||||
#else
|
||||
#define MAP_CACHE_SET(index, pos)
|
||||
#endif
|
||||
|
||||
// This table of sizes is used to control the growth of hash tables.
|
||||
// The first set of sizes are chosen so the allocation fits exactly in a
|
||||
// 4-word GC block, and it's not so important for these small values to be
|
||||
@ -134,10 +155,22 @@ 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 *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
|
||||
mp_map_elem_t *MICROPY_WRAP_MP_MAP_LOOKUP(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);
|
||||
|
||||
#if MICROPY_OPT_MAP_LOOKUP_CACHE
|
||||
// Try the cache for lookup or add-if-not-found.
|
||||
if (lookup_kind != MP_MAP_LOOKUP_REMOVE_IF_FOUND && map->alloc) {
|
||||
mp_map_elem_t *slot = MAP_CACHE_GET(map, index);
|
||||
// Note: Just comparing key for value equality will have false negatives, but
|
||||
// these will be handled by the regular path below.
|
||||
if (slot->key == index) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Work out if we can compare just pointers
|
||||
bool compare_only_ptrs = map->all_keys_are_qstrs;
|
||||
if (compare_only_ptrs) {
|
||||
@ -174,6 +207,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m
|
||||
elem->value = value;
|
||||
}
|
||||
#endif
|
||||
MAP_CACHE_SET(index, elem - map->table);
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
@ -256,6 +290,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m
|
||||
}
|
||||
// keep slot->value so that caller can access it if needed
|
||||
}
|
||||
MAP_CACHE_SET(index, pos);
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,15 @@ set(MICROPY_QSTRDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h")
|
||||
set(MICROPY_QSTRDEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h")
|
||||
set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h")
|
||||
|
||||
# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen
|
||||
# manifest handling is at the end of this file.
|
||||
if(MICROPY_FROZEN_MANIFEST)
|
||||
target_compile_definitions(${MICROPY_TARGET} PUBLIC
|
||||
MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
|
||||
MICROPY_MODULE_FROZEN_MPY=\(1\)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Provide defaults for preprocessor flags if not already defined
|
||||
if(NOT MICROPY_CPP_FLAGS)
|
||||
get_target_property(MICROPY_CPP_INC ${MICROPY_TARGET} INCLUDE_DIRECTORIES)
|
||||
@ -120,10 +129,7 @@ if(MICROPY_FROZEN_MANIFEST)
|
||||
${MICROPY_FROZEN_CONTENT}
|
||||
)
|
||||
|
||||
target_compile_definitions(${MICROPY_TARGET} PUBLIC
|
||||
MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
|
||||
MICROPY_MODULE_FROZEN_MPY=\(1\)
|
||||
)
|
||||
# Note: target_compile_definitions already added earlier.
|
||||
|
||||
if(NOT MICROPY_LIB_DIR)
|
||||
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)
|
||||
|
@ -125,46 +125,18 @@ $(MICROPY_MPYCROSS_DEPENDENCY):
|
||||
$(MAKE) -C $(dir $@)
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_MANIFEST),)
|
||||
# to build frozen_content.c from a manifest
|
||||
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
|
||||
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
|
||||
|
||||
ifneq ($(FROZEN_DIR),)
|
||||
$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)
|
||||
$(error Support for FROZEN_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIR),)
|
||||
$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST)
|
||||
endif
|
||||
$(error Support for FROZEN_MPY_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_DIR),)
|
||||
$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST)
|
||||
$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS)
|
||||
$(STEPECHO) "Generating $@"
|
||||
$(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIRS),)
|
||||
# Copy all the modules and single python files to freeze to a common area, omitting top-level dirs (the repo names).
|
||||
# Do any preprocessing necessary: currently, this adds version information, removes examples, and
|
||||
# non-library .py files in the modules (setup.py and conf.py)
|
||||
# Then compile .mpy files from all the .py files, placing them in the same directories as the .py files.
|
||||
$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
|
||||
$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
|
||||
$(Q)$(MKDIR) -p $@
|
||||
$(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
|
||||
$(Q)$(CD) $@ && \
|
||||
$(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \
|
||||
xargs -n1 "$(abspath $(MICROPY_MPYCROSS_DEPENDENCY))" $(MPY_CROSS_FLAGS)
|
||||
|
||||
# to build frozen_mpy.c from all .mpy files
|
||||
# You need to define MPY_TOOL_LONGINT_IMPL in mpconfigport.mk
|
||||
# if the default will not work (mpz is the default).
|
||||
$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h $(TOP)/tools/mpy-tool.py
|
||||
$(STEPECHO) "Creating $@"
|
||||
$(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
|
||||
ifneq ($(FROZEN_MANIFEST),)
|
||||
# to build frozen_content.c from a manifest
|
||||
$(BUILD)/frozen_content.c: FORCE $(FROZEN_MANIFEST) $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY) $(TOP)/tools/makemanifest.py
|
||||
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
|
||||
endif
|
||||
|
||||
ifneq ($(PROG),)
|
||||
@ -220,27 +192,6 @@ clean:
|
||||
$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
|
||||
.PHONY: clean
|
||||
|
||||
# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup.
|
||||
# We run rmdir below to avoid empty backup dir (it will silently fail if backup
|
||||
# is non-empty).
|
||||
clean-frozen:
|
||||
if [ -n "$(FROZEN_MPY_DIR)" ]; then \
|
||||
backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
|
||||
cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
|
||||
| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
|
||||
rmdir ../$$backup_dir 2>/dev/null || true; \
|
||||
git clean -d -f .; \
|
||||
fi
|
||||
|
||||
if [ -n "$(FROZEN_DIR)" ]; then \
|
||||
backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
|
||||
cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
|
||||
| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
|
||||
rmdir ../$$backup_dir 2>/dev/null || true; \
|
||||
git clean -d -f .; \
|
||||
fi
|
||||
.PHONY: clean-frozen
|
||||
|
||||
print-cfg:
|
||||
$(ECHO) "PY_SRC = $(PY_SRC)"
|
||||
$(ECHO) "BUILD = $(BUILD)"
|
||||
|
@ -786,6 +786,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
|
||||
|
||||
// Extra builtins as defined by a port
|
||||
MICROPY_PORT_BUILTINS
|
||||
MICROPY_PORT_EXTRA_BUILTINS
|
||||
};
|
||||
|
||||
MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table);
|
||||
|
47
py/modio.c
47
py/modio.c
@ -212,50 +212,6 @@ STATIC const mp_obj_type_t mp_type_bufwriter = {
|
||||
};
|
||||
#endif // MICROPY_PY_IO_BUFFEREDWRITER
|
||||
|
||||
#if MICROPY_PY_IO_RESOURCE_STREAM
|
||||
STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
|
||||
VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);
|
||||
size_t len;
|
||||
|
||||
// As an extension to pkg_resources.resource_stream(), we support
|
||||
// package parameter being None, the path_in is interpreted as a
|
||||
// raw path.
|
||||
if (package_in != mp_const_none) {
|
||||
// Pass "True" as sentinel value in fromlist to force returning of leaf module
|
||||
mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0));
|
||||
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(pkg, MP_QSTR___path__, dest);
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
|
||||
const char *path = mp_obj_str_get_data(dest[0], &len);
|
||||
vstr_add_strn(&path_buf, path, len);
|
||||
vstr_add_byte(&path_buf, '/');
|
||||
}
|
||||
|
||||
const char *path = mp_obj_str_get_data(path_in, &len);
|
||||
vstr_add_strn(&path_buf, path, len);
|
||||
|
||||
size_t file_len;
|
||||
const char *data = mp_find_frozen_str(path_buf.buf, path_buf.len, &file_len);
|
||||
if (data != NULL) {
|
||||
mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
|
||||
o->base.type = &mp_type_bytesio;
|
||||
o->vstr = m_new_obj(vstr_t);
|
||||
vstr_init_fixed_buf(o->vstr, file_len + 1, (char *)data);
|
||||
o->vstr->len = file_len;
|
||||
o->pos = 0;
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);
|
||||
return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
|
||||
#if CIRCUITPY
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_io) },
|
||||
@ -268,9 +224,6 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
|
||||
#if MICROPY_PY_IO_IOBASE
|
||||
{ MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) },
|
||||
#endif
|
||||
#if MICROPY_PY_IO_RESOURCE_STREAM
|
||||
{ MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_IO_FILEIO
|
||||
{ MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) },
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
|
@ -158,7 +158,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_SETTRACE
|
||||
// settrace(tracefunc): Set the system’s trace function.
|
||||
// settrace(tracefunc): Set the system's trace function.
|
||||
STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) {
|
||||
return mp_prof_settrace(obj);
|
||||
}
|
||||
|
376
py/mpconfig.h
376
py/mpconfig.h
@ -50,6 +50,31 @@
|
||||
#define CIRCUITPY 0
|
||||
#endif
|
||||
|
||||
// Disable all optional features (i.e. minimal port).
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0)
|
||||
// Only enable core features (constrained flash, e.g. STM32L072)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10)
|
||||
// Enable most common features (small on-device flash, e.g. STM32F411)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20)
|
||||
// Enable convenience features (medium on-device flash, e.g. STM32F405)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30)
|
||||
// Enable all common features (large/external flash, rp2, unix)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40)
|
||||
// Enable everything (e.g. coverage)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50)
|
||||
|
||||
// Ports/boards should set this, but default to level=core.
|
||||
#ifndef MICROPY_CONFIG_ROM_LEVEL
|
||||
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Helper macros for "have at least this level".
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
|
||||
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING)
|
||||
|
||||
// Any options not explicitly set in mpconfigport.h will get default
|
||||
// values below.
|
||||
|
||||
@ -144,7 +169,7 @@
|
||||
// Support automatic GC when reaching allocation threshold,
|
||||
// configurable by gc.threshold().
|
||||
#ifndef MICROPY_GC_ALLOC_THRESHOLD
|
||||
#define MICROPY_GC_ALLOC_THRESHOLD (1)
|
||||
#define MICROPY_GC_ALLOC_THRESHOLD (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Number of bytes to allocate initially when creating new chunks to store
|
||||
@ -243,7 +268,11 @@
|
||||
|
||||
// Number of bytes used to store qstr hash
|
||||
#ifndef MICROPY_QSTR_BYTES_IN_HASH
|
||||
#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (2)
|
||||
#else
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Avoid using C stack when making Python function calls. C stack still
|
||||
@ -385,7 +414,7 @@
|
||||
|
||||
// Whether to include the compiler
|
||||
#ifndef MICROPY_ENABLE_COMPILER
|
||||
#define MICROPY_ENABLE_COMPILER (1)
|
||||
#define MICROPY_ENABLE_COMPILER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether the compiler is dynamically configurable (ie at runtime)
|
||||
@ -396,49 +425,47 @@
|
||||
|
||||
// Configure dynamic compiler macros
|
||||
#if MICROPY_DYNAMIC_COMPILER
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode)
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode)
|
||||
#else
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
#endif
|
||||
|
||||
// Whether to enable constant folding; eg 1+2 rewritten as 3
|
||||
#ifndef MICROPY_COMP_CONST_FOLDING
|
||||
#define MICROPY_COMP_CONST_FOLDING (1)
|
||||
#define MICROPY_COMP_CONST_FOLDING (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable optimisations for constant literals, eg OrderedDict
|
||||
#ifndef MICROPY_COMP_CONST_LITERAL
|
||||
#define MICROPY_COMP_CONST_LITERAL (1)
|
||||
#define MICROPY_COMP_CONST_LITERAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable lookup of constants in modules; eg module.CONST
|
||||
#ifndef MICROPY_COMP_MODULE_CONST
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable constant optimisation; id = const(value)
|
||||
#ifndef MICROPY_COMP_CONST
|
||||
#define MICROPY_COMP_CONST (1)
|
||||
#define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable optimisation of: a, b = c, d
|
||||
// Costs 124 bytes (Thumb2)
|
||||
#ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
|
||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable optimisation of: a, b, c = d, e, f
|
||||
// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2)
|
||||
#ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable optimisation of: return a if b else c
|
||||
// Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use
|
||||
#ifndef MICROPY_COMP_RETURN_IF_EXPR
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (0)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to include parsing of f-string literals
|
||||
@ -511,23 +538,36 @@
|
||||
#define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (0)
|
||||
#endif
|
||||
|
||||
// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,
|
||||
// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and
|
||||
// uses a bit of extra code ROM, but greatly improves lookup speed.
|
||||
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
// Optimise the fast path for loading attributes from instance types. Increases
|
||||
// Thumb2 code size by about 48 bytes.
|
||||
#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
|
||||
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Use extra RAM to cache map lookups by remembering the likely location of
|
||||
// the index. Avoids the hash computation on unordered maps, and avoids the
|
||||
// linear search on ordered (especially in-ROM) maps. Can provide a +10-15%
|
||||
// performance improvement on benchmarks involving lots of attribute access
|
||||
// or dictionary lookup.
|
||||
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
|
||||
#define MICROPY_OPT_MAP_LOOKUP_CACHE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// How much RAM (in bytes) to use for the map lookup cache.
|
||||
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE
|
||||
#define MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE (128)
|
||||
#endif
|
||||
|
||||
// Whether to use fast versions of bitwise operations (and, or, xor) when the
|
||||
// arguments are both positive. Increases Thumb2 code size by about 250 bytes.
|
||||
#ifndef MICROPY_OPT_MPZ_BITWISE
|
||||
#define MICROPY_OPT_MPZ_BITWISE (0)
|
||||
#define MICROPY_OPT_MPZ_BITWISE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
|
||||
// Whether math.factorial is large, fast and recursive (1) or small and slow (0).
|
||||
#ifndef MICROPY_OPT_MATH_FACTORIAL
|
||||
#define MICROPY_OPT_MATH_FACTORIAL (0)
|
||||
#define MICROPY_OPT_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -537,7 +577,7 @@
|
||||
// When disabled, only importing of built-in modules is supported
|
||||
// When enabled, a port must implement mp_import_stat (among other things)
|
||||
#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT
|
||||
#define MICROPY_ENABLE_EXTERNAL_IMPORT (1)
|
||||
#define MICROPY_ENABLE_EXTERNAL_IMPORT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to use the POSIX reader for importing files
|
||||
@ -587,9 +627,14 @@
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
#endif
|
||||
|
||||
// Hook to run code during time consuming garbage collector operations
|
||||
#ifndef MICROPY_GC_HOOK_LOOP
|
||||
#define MICROPY_GC_HOOK_LOOP
|
||||
#endif
|
||||
|
||||
// Whether to enable finalisers in the garbage collector (ie call __del__)
|
||||
#ifndef MICROPY_ENABLE_FINALISER
|
||||
#define MICROPY_ENABLE_FINALISER (0)
|
||||
#define MICROPY_ENABLE_FINALISER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable a separate allocator for the Python stack.
|
||||
@ -606,7 +651,7 @@
|
||||
// Whether to check C stack usage. C stack used for calling Python functions,
|
||||
// etc. Not checking means segfault on overflow.
|
||||
#ifndef MICROPY_STACK_CHECK
|
||||
#define MICROPY_STACK_CHECK (0)
|
||||
#define MICROPY_STACK_CHECK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to measure maximum stack excursion
|
||||
@ -626,7 +671,7 @@
|
||||
|
||||
// Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function
|
||||
#ifndef MICROPY_KBD_EXCEPTION
|
||||
#define MICROPY_KBD_EXCEPTION (0)
|
||||
#define MICROPY_KBD_EXCEPTION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt
|
||||
@ -637,7 +682,7 @@
|
||||
|
||||
// Whether to include REPL helper function
|
||||
#ifndef MICROPY_HELPER_REPL
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_REPL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Allow enabling debug prints after each REPL line
|
||||
@ -647,7 +692,7 @@
|
||||
|
||||
// Whether to include emacs-style readline behavior in REPL
|
||||
#ifndef MICROPY_REPL_EMACS_KEYS
|
||||
#define MICROPY_REPL_EMACS_KEYS (0)
|
||||
#define MICROPY_REPL_EMACS_KEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to include emacs-style word movement/kill readline behavior in REPL.
|
||||
@ -667,7 +712,7 @@
|
||||
|
||||
// Whether to implement auto-indent in REPL
|
||||
#ifndef MICROPY_REPL_AUTO_INDENT
|
||||
#define MICROPY_REPL_AUTO_INDENT (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether port requires event-driven REPL functions
|
||||
@ -696,7 +741,7 @@ typedef long long mp_longint_impl_t;
|
||||
// Whether to include information in the byte code to determine source
|
||||
// line number (increases RAM usage, but doesn't slow byte code execution)
|
||||
#ifndef MICROPY_ENABLE_SOURCE_LINE
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to include doc strings (increases RAM usage)
|
||||
@ -714,7 +759,13 @@ typedef long long mp_longint_impl_t;
|
||||
#define MICROPY_ERROR_REPORTING_DETAILED (3)
|
||||
|
||||
#ifndef MICROPY_ERROR_REPORTING
|
||||
#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
|
||||
#elif MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
|
||||
#else
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Whether issue warnings during compiling/execution
|
||||
@ -770,7 +821,7 @@ typedef double mp_float_t;
|
||||
// TODO: Originally intended as generic category to not
|
||||
// add bunch of once-off options. May need refactoring later
|
||||
#ifndef MICROPY_CPYTHON_COMPAT
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#define MICROPY_CPYTHON_COMPAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Perform full checks as done by CPython. Disabling this
|
||||
@ -779,12 +830,12 @@ typedef double mp_float_t;
|
||||
// grave issues (in other words, only user app should be,
|
||||
// affected, not system).
|
||||
#ifndef MICROPY_FULL_CHECKS
|
||||
#define MICROPY_FULL_CHECKS (1)
|
||||
#define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether POSIX-semantics non-blocking streams are supported
|
||||
#ifndef MICROPY_STREAMS_NON_BLOCK
|
||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||
#define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide stream functions with POSIX-like signatures
|
||||
@ -795,17 +846,23 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to call __init__ when importing builtin modules for the first time
|
||||
#ifndef MICROPY_MODULE_BUILTIN_INIT
|
||||
#define MICROPY_MODULE_BUILTIN_INIT (0)
|
||||
#define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support module-level __getattr__ (see PEP 562)
|
||||
#ifndef MICROPY_MODULE_GETATTR
|
||||
#define MICROPY_MODULE_GETATTR (1)
|
||||
#define MICROPY_MODULE_GETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether module weak links are supported
|
||||
#ifndef MICROPY_MODULE_WEAK_LINKS
|
||||
#define MICROPY_MODULE_WEAK_LINKS (0)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable importing foo.py with __name__ set to '__main__'
|
||||
// Used by the unix port for the -m flag.
|
||||
#ifndef MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
|
||||
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (0)
|
||||
#endif
|
||||
|
||||
// Whether frozen modules are supported in the form of strings
|
||||
@ -825,7 +882,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether you can override builtins in the builtins module
|
||||
#ifndef MICROPY_CAN_OVERRIDE_BUILTINS
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to check that the "self" argument of a builtin method has the
|
||||
@ -834,7 +891,7 @@ typedef double mp_float_t;
|
||||
// list.append([], 1). Without this check such calls will have undefined
|
||||
// behaviour (usually segfault) if the first argument is the wrong type.
|
||||
#ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to use internally defined errno's (otherwise system provided ones)
|
||||
@ -849,7 +906,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Support for internal scheduler
|
||||
#ifndef MICROPY_ENABLE_SCHEDULER
|
||||
#define MICROPY_ENABLE_SCHEDULER (0)
|
||||
#define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Maximum number of entries in the scheduler
|
||||
@ -884,41 +941,41 @@ typedef double mp_float_t;
|
||||
// inheritance makes some C functions inherently recursive, and adds a bit of
|
||||
// code overhead.
|
||||
#ifndef MICROPY_MULTIPLE_INHERITANCE
|
||||
#define MICROPY_MULTIPLE_INHERITANCE (1)
|
||||
#define MICROPY_MULTIPLE_INHERITANCE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to implement attributes on functions
|
||||
#ifndef MICROPY_PY_FUNCTION_ATTRS
|
||||
#define MICROPY_PY_FUNCTION_ATTRS (0)
|
||||
#define MICROPY_PY_FUNCTION_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support the descriptors __get__, __set__, __delete__
|
||||
// This costs some code size and makes load/store/delete of instance
|
||||
// attributes slower for the classes that use this feature
|
||||
#ifndef MICROPY_PY_DESCRIPTORS
|
||||
#define MICROPY_PY_DESCRIPTORS (0)
|
||||
#define MICROPY_PY_DESCRIPTORS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support class __delattr__ and __setattr__ methods
|
||||
// This costs some code size and makes store/delete of instance
|
||||
// attributes slower for the classes that use this feature
|
||||
#ifndef MICROPY_PY_DELATTR_SETATTR
|
||||
#define MICROPY_PY_DELATTR_SETATTR (0)
|
||||
#define MICROPY_PY_DELATTR_SETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Support for async/await/async for/async with
|
||||
#ifndef MICROPY_PY_ASYNC_AWAIT
|
||||
#define MICROPY_PY_ASYNC_AWAIT (1)
|
||||
#define MICROPY_PY_ASYNC_AWAIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+)
|
||||
#ifndef MICROPY_PY_FSTRINGS
|
||||
#define MICROPY_PY_FSTRINGS (0)
|
||||
#define MICROPY_PY_FSTRINGS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Support for assignment expressions with := (see PEP 572, Python 3.8+)
|
||||
#ifndef MICROPY_PY_ASSIGN_EXPR
|
||||
#define MICROPY_PY_ASSIGN_EXPR (1)
|
||||
#define MICROPY_PY_ASSIGN_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Non-standard .pend_throw() method for generators, allowing for
|
||||
@ -927,7 +984,7 @@ typedef double mp_float_t;
|
||||
// to generator's .send() or .__next__(). (This is useful to implement
|
||||
// async schedulers.)
|
||||
#ifndef MICROPY_PY_GENERATOR_PEND_THROW
|
||||
#define MICROPY_PY_GENERATOR_PEND_THROW (1)
|
||||
#define MICROPY_PY_GENERATOR_PEND_THROW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Issue a warning when comparing str and bytes objects
|
||||
@ -937,7 +994,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether str object is proper unicode
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to check for valid UTF-8 when converting bytes to str
|
||||
@ -947,42 +1004,42 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether str.center() method provided
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_CENTER
|
||||
#define MICROPY_PY_BUILTINS_STR_CENTER (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_CENTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether str.count() method provided
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_COUNT
|
||||
#define MICROPY_PY_BUILTINS_STR_COUNT (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_COUNT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether str % (...) formatting operator provided
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO
|
||||
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether str.partition()/str.rpartition() method provided
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_PARTITION
|
||||
#define MICROPY_PY_BUILTINS_STR_PARTITION (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_PARTITION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether str.splitlines() method provided
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support bytearray object
|
||||
#ifndef MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support dict.fromkeys() class method
|
||||
#ifndef MICROPY_PY_BUILTINS_DICT_FROMKEYS
|
||||
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1)
|
||||
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support memoryview object
|
||||
#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support memoryview.itemsize attribute
|
||||
@ -992,39 +1049,39 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to support set object
|
||||
#ifndef MICROPY_PY_BUILTINS_SET
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
#define MICROPY_PY_BUILTINS_SET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support slice subscript operators and slice object
|
||||
#ifndef MICROPY_PY_BUILTINS_SLICE
|
||||
#define MICROPY_PY_BUILTINS_SLICE (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support slice attribute read access,
|
||||
// i.e. slice.start, slice.stop, slice.step
|
||||
#ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS
|
||||
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support the .indices(len) method on slice objects
|
||||
#ifndef MICROPY_PY_BUILTINS_SLICE_INDICES
|
||||
#define MICROPY_PY_BUILTINS_SLICE_INDICES (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE_INDICES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support frozenset object
|
||||
#ifndef MICROPY_PY_BUILTINS_FROZENSET
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support property object
|
||||
#ifndef MICROPY_PY_BUILTINS_PROPERTY
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to implement the start/stop/step attributes (readback) on
|
||||
// the "range" builtin type. Rarely used, and costs ~60 bytes (x86).
|
||||
#ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS
|
||||
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
|
||||
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support binary ops [only (in)equality is defined] between range
|
||||
@ -1042,7 +1099,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120
|
||||
#ifndef MICROPY_PY_BUILTINS_ROUND_INT
|
||||
#define MICROPY_PY_BUILTINS_ROUND_INT (0)
|
||||
#define MICROPY_PY_BUILTINS_ROUND_INT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support complete set of special methods for user
|
||||
@ -1051,7 +1108,7 @@ typedef double mp_float_t;
|
||||
// "Reverse" methods are controlled by
|
||||
// MICROPY_PY_REVERSE_SPECIAL_METHODS below.
|
||||
#ifndef MICROPY_PY_ALL_SPECIAL_METHODS
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support all inplace arithmetic operarion methods
|
||||
@ -1064,17 +1121,17 @@ typedef double mp_float_t;
|
||||
// (__radd__, etc.). Additionally gated by
|
||||
// MICROPY_PY_ALL_SPECIAL_METHODS.
|
||||
#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
|
||||
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
|
||||
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support compile function
|
||||
#ifndef MICROPY_PY_BUILTINS_COMPILE
|
||||
#define MICROPY_PY_BUILTINS_COMPILE (0)
|
||||
#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support enumerate function(type)
|
||||
#ifndef MICROPY_PY_BUILTINS_ENUMERATE
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support eval and exec functions
|
||||
@ -1085,43 +1142,43 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to support the Python 2 execfile function
|
||||
#ifndef MICROPY_PY_BUILTINS_EXECFILE
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (0)
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support filter function(type)
|
||||
#ifndef MICROPY_PY_BUILTINS_FILTER
|
||||
#define MICROPY_PY_BUILTINS_FILTER (1)
|
||||
#define MICROPY_PY_BUILTINS_FILTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support reversed function(type)
|
||||
#ifndef MICROPY_PY_BUILTINS_REVERSED
|
||||
#define MICROPY_PY_BUILTINS_REVERSED (1)
|
||||
#define MICROPY_PY_BUILTINS_REVERSED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to define "NotImplemented" special constant
|
||||
#ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED
|
||||
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0)
|
||||
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide the built-in input() function. The implementation of this
|
||||
// uses shared/readline, so can only be enabled if the port uses this readline.
|
||||
#ifndef MICROPY_PY_BUILTINS_INPUT
|
||||
#define MICROPY_PY_BUILTINS_INPUT (0)
|
||||
#define MICROPY_PY_BUILTINS_INPUT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support min/max functions
|
||||
#ifndef MICROPY_PY_BUILTINS_MIN_MAX
|
||||
#define MICROPY_PY_BUILTINS_MIN_MAX (1)
|
||||
#define MICROPY_PY_BUILTINS_MIN_MAX (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Support for calls to pow() with 3 integer arguments
|
||||
#ifndef MICROPY_PY_BUILTINS_POW3
|
||||
#define MICROPY_PY_BUILTINS_POW3 (0)
|
||||
#define MICROPY_PY_BUILTINS_POW3 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide the help function
|
||||
#ifndef MICROPY_PY_BUILTINS_HELP
|
||||
#define MICROPY_PY_BUILTINS_HELP (0)
|
||||
#define MICROPY_PY_BUILTINS_HELP (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Use this to configure the help text shown for help(). It should be a
|
||||
@ -1132,17 +1189,17 @@ typedef double mp_float_t;
|
||||
|
||||
// Add the ability to list the available modules when executing help('modules')
|
||||
#ifndef MICROPY_PY_BUILTINS_HELP_MODULES
|
||||
#define MICROPY_PY_BUILTINS_HELP_MODULES (0)
|
||||
#define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to set __file__ for imported modules
|
||||
#ifndef MICROPY_PY___FILE__
|
||||
#define MICROPY_PY___FILE__ (1)
|
||||
#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide mem-info related functions in micropython module
|
||||
#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "micropython.stack_use" function
|
||||
@ -1159,13 +1216,13 @@ typedef double mp_float_t;
|
||||
// underlying code is shared with "bytearray" builtin type, so to
|
||||
// get real savings, it should be disabled too.
|
||||
#ifndef MICROPY_PY_ARRAY
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#define MICROPY_PY_ARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support slice assignments for array (and bytearray).
|
||||
// This is rarely used, but adds ~0.5K of code.
|
||||
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support nonstandard typecodes "O", "P" and "S"
|
||||
@ -1177,22 +1234,22 @@ typedef double mp_float_t;
|
||||
// Whether to support attrtuple type (MicroPython extension)
|
||||
// It provides space-efficient tuples with attribute access
|
||||
#ifndef MICROPY_PY_ATTRTUPLE
|
||||
#define MICROPY_PY_ATTRTUPLE (1)
|
||||
#define MICROPY_PY_ATTRTUPLE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "collections" module
|
||||
#ifndef MICROPY_PY_COLLECTIONS
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
#define MICROPY_PY_COLLECTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "ucollections.deque" type
|
||||
#ifndef MICROPY_PY_COLLECTIONS_DEQUE
|
||||
#define MICROPY_PY_COLLECTIONS_DEQUE (0)
|
||||
#define MICROPY_PY_COLLECTIONS_DEQUE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "collections.OrderedDict" type
|
||||
#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide the _asdict function for namedtuple
|
||||
@ -1202,22 +1259,22 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide "math" module
|
||||
#ifndef MICROPY_PY_MATH
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MICROPY_PY_MATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide special math functions: math.{erf,erfc,gamma,lgamma}
|
||||
#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS
|
||||
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0)
|
||||
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide math.factorial function
|
||||
#ifndef MICROPY_PY_MATH_FACTORIAL
|
||||
#define MICROPY_PY_MATH_FACTORIAL (0)
|
||||
#define MICROPY_PY_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide math.isclose function
|
||||
#ifndef MICROPY_PY_MATH_ISCLOSE
|
||||
#define MICROPY_PY_MATH_ISCLOSE (0)
|
||||
#define MICROPY_PY_MATH_ISCLOSE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide fix for atan2 Inf handling.
|
||||
@ -1242,12 +1299,12 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide "cmath" module
|
||||
#ifndef MICROPY_PY_CMATH
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_CMATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "gc" module
|
||||
#ifndef MICROPY_PY_GC
|
||||
#define MICROPY_PY_GC (1)
|
||||
#define MICROPY_PY_GC (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to return number of collected objects from gc.collect()
|
||||
@ -1257,28 +1314,17 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide "io" module
|
||||
#ifndef MICROPY_PY_IO
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_IO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io.IOBase" class to support user streams
|
||||
#ifndef MICROPY_PY_IO_IOBASE
|
||||
#define MICROPY_PY_IO_IOBASE (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "uio.resource_stream()" function with
|
||||
// the semantics of CPython's pkg_resources.resource_stream()
|
||||
// (allows to access binary resources in frozen source packages).
|
||||
// Note that the same functionality can be achieved in "pure
|
||||
// Python" by prepocessing binary resources into Python source
|
||||
// and bytecode-freezing it (with a simple helper module available
|
||||
// e.g. in micropython-lib).
|
||||
#ifndef MICROPY_PY_IO_RESOURCE_STREAM
|
||||
#define MICROPY_PY_IO_RESOURCE_STREAM (0)
|
||||
#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io.FileIO" class
|
||||
#ifndef MICROPY_PY_IO_FILEIO
|
||||
#define MICROPY_PY_IO_FILEIO (0)
|
||||
#define MICROPY_PY_IO_FILEIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "io.BytesIO" class
|
||||
@ -1293,17 +1339,22 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide "struct" module
|
||||
#ifndef MICROPY_PY_STRUCT
|
||||
#define MICROPY_PY_STRUCT (1)
|
||||
#define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys" module
|
||||
#ifndef MICROPY_PY_SYS
|
||||
#define MICROPY_PY_SYS (1)
|
||||
#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init()
|
||||
#ifndef MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
|
||||
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (MICROPY_PY_SYS)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.maxsize" constant
|
||||
#ifndef MICROPY_PY_SYS_MAXSIZE
|
||||
#define MICROPY_PY_SYS_MAXSIZE (0)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.modules" dictionary
|
||||
@ -1339,18 +1390,18 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide sys.{stdin,stdout,stderr} objects
|
||||
#ifndef MICROPY_PY_SYS_STDFILES
|
||||
#define MICROPY_PY_SYS_STDFILES (0)
|
||||
#define MICROPY_PY_SYS_STDFILES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide sys.{stdin,stdout,stderr}.buffer object
|
||||
// This is implemented per-port
|
||||
#ifndef MICROPY_PY_SYS_STDIO_BUFFER
|
||||
#define MICROPY_PY_SYS_STDIO_BUFFER (0)
|
||||
#define MICROPY_PY_SYS_STDIO_BUFFER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide "uerrno" module
|
||||
#ifndef MICROPY_PY_UERRNO
|
||||
#define MICROPY_PY_UERRNO (0)
|
||||
#define MICROPY_PY_UERRNO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide the uerrno.errorcode dict
|
||||
@ -1360,7 +1411,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to provide "uselect" module (baremetal implementation)
|
||||
#ifndef MICROPY_PY_USELECT
|
||||
#define MICROPY_PY_USELECT (0)
|
||||
#define MICROPY_PY_USELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to enable the select() function in the "uselect" module (baremetal
|
||||
@ -1406,11 +1457,11 @@ typedef double mp_float_t;
|
||||
// Extended modules
|
||||
|
||||
#ifndef MICROPY_PY_UASYNCIO
|
||||
#define MICROPY_PY_UASYNCIO (0)
|
||||
#define MICROPY_PY_UASYNCIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UCTYPES
|
||||
#define MICROPY_PY_UCTYPES (0)
|
||||
#define MICROPY_PY_UCTYPES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to provide SHORT, INT, LONG, etc. types in addition to
|
||||
@ -1420,11 +1471,11 @@ typedef double mp_float_t;
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UZLIB
|
||||
#define MICROPY_PY_UZLIB (0)
|
||||
#define MICROPY_PY_UZLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UJSON
|
||||
#define MICROPY_PY_UJSON (0)
|
||||
#define MICROPY_PY_UJSON (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to support the "separators" argument to dump, dumps
|
||||
@ -1437,7 +1488,7 @@ typedef double mp_float_t;
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_URE
|
||||
#define MICROPY_PY_URE (0)
|
||||
#define MICROPY_PY_URE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_URE_DEBUG
|
||||
@ -1453,20 +1504,20 @@ typedef double mp_float_t;
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_URE_SUB
|
||||
#define MICROPY_PY_URE_SUB (0)
|
||||
#define MICROPY_PY_URE_SUB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UHEAPQ
|
||||
#define MICROPY_PY_UHEAPQ (0)
|
||||
#define MICROPY_PY_UHEAPQ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Optimized heap queue for relative timestamps
|
||||
// Optimized heap queue for relative timestamps (only used by uasyncio v2)
|
||||
#ifndef MICROPY_PY_UTIMEQ
|
||||
#define MICROPY_PY_UTIMEQ (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UHASHLIB
|
||||
#define MICROPY_PY_UHASHLIB (0)
|
||||
#define MICROPY_PY_UHASHLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UHASHLIB_MD5
|
||||
@ -1495,25 +1546,70 @@ typedef double mp_float_t;
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UBINASCII
|
||||
#define MICROPY_PY_UBINASCII (0)
|
||||
#define MICROPY_PY_UBINASCII (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Depends on MICROPY_PY_UZLIB
|
||||
#ifndef MICROPY_PY_UBINASCII_CRC32
|
||||
#define MICROPY_PY_UBINASCII_CRC32 (0)
|
||||
#define MICROPY_PY_UBINASCII_CRC32 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_URANDOM
|
||||
#define MICROPY_PY_URANDOM (0)
|
||||
#define MICROPY_PY_URANDOM (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to include: randrange, randint, choice, random, uniform
|
||||
#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_MACHINE
|
||||
#define MICROPY_PY_MACHINE (0)
|
||||
#endif
|
||||
|
||||
// Whether to include: bitstream
|
||||
#ifndef MICROPY_PY_MACHINE_BITSTREAM
|
||||
#define MICROPY_PY_MACHINE_BITSTREAM (0)
|
||||
#endif
|
||||
|
||||
// Whether to include: time_pulse_us
|
||||
#ifndef MICROPY_PY_MACHINE_PULSE
|
||||
#define MICROPY_PY_MACHINE_PULSE (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_MACHINE_I2C
|
||||
#define MICROPY_PY_MACHINE_I2C (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide the "machine.SoftI2C" class
|
||||
#ifndef MICROPY_PY_MACHINE_SOFTI2C
|
||||
#define MICROPY_PY_MACHINE_SOFTI2C (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_MACHINE_SPI
|
||||
#define MICROPY_PY_MACHINE_SPI (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide the "machine.SoftSPI" class
|
||||
#ifndef MICROPY_PY_MACHINE_SOFTSPI
|
||||
#define MICROPY_PY_MACHINE_SOFTSPI (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_USSL
|
||||
#define MICROPY_PY_USSL (0)
|
||||
#endif
|
||||
|
||||
// Whether to add finaliser code to ussl objects
|
||||
#ifndef MICROPY_PY_USSL_FINALISER
|
||||
#define MICROPY_PY_USSL_FINALISER (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UWEBSOCKET
|
||||
#define MICROPY_PY_UWEBSOCKET (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_FRAMEBUF
|
||||
#define MICROPY_PY_FRAMEBUF (0)
|
||||
#define MICROPY_PY_FRAMEBUF (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_BTREE
|
||||
@ -1523,6 +1619,12 @@ typedef double mp_float_t;
|
||||
#ifndef MICROPY_HW_ENABLE_USB
|
||||
#define MICROPY_HW_ENABLE_USB (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide the low-level "_onewire" module
|
||||
#ifndef MICROPY_PY_ONEWIRE
|
||||
#define MICROPY_PY_ONEWIRE (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to add builtins */
|
||||
|
||||
@ -1531,6 +1633,12 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PORT_BUILTINS
|
||||
#endif
|
||||
|
||||
// Additional builtin function definitions for extension by command-line, boards or variants.
|
||||
// See modbuiltins.c:mp_module_builtins_globals_table for format.
|
||||
#ifndef MICROPY_PORT_EXTRA_BUILTINS
|
||||
#define MICROPY_PORT_EXTRA_BUILTINS
|
||||
#endif
|
||||
|
||||
// Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format.
|
||||
#ifndef MICROPY_PORT_BUILTIN_MODULES
|
||||
#define MICROPY_PORT_BUILTIN_MODULES
|
||||
@ -1549,6 +1657,30 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to wrap functions with attributes */
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_BINARY_OP
|
||||
#define MICROPY_WRAP_MP_BINARY_OP(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE
|
||||
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_LOAD_GLOBAL
|
||||
#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_LOAD_NAME
|
||||
#define MICROPY_WRAP_MP_LOAD_NAME(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_MAP_LOOKUP
|
||||
#define MICROPY_WRAP_MP_MAP_LOOKUP(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_OBJ_GET_TYPE
|
||||
#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
|
||||
#define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
|
||||
#endif
|
||||
|
11
py/mpstate.h
11
py/mpstate.h
@ -44,7 +44,6 @@
|
||||
#if MICROPY_DYNAMIC_COMPILER
|
||||
typedef struct mp_dynamic_compiler_t {
|
||||
uint8_t small_int_bits; // must be <= host small_int_bits
|
||||
bool opt_cache_map_lookup_in_bytecode;
|
||||
bool py_builtins_str_unicode;
|
||||
uint8_t native_arch;
|
||||
uint8_t nlr_buf_num_regs;
|
||||
@ -165,9 +164,12 @@ typedef struct _mp_state_vm_t {
|
||||
// dictionary for the __main__ module
|
||||
mp_obj_dict_t dict_main;
|
||||
|
||||
// these two lists must be initialised per port, after the call to mp_init
|
||||
#if MICROPY_PY_SYS
|
||||
// If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is not enabled then these two lists
|
||||
// must be initialised after the call to mp_init.
|
||||
mp_obj_list_t mp_sys_path_obj;
|
||||
mp_obj_list_t mp_sys_argv_obj;
|
||||
#endif
|
||||
|
||||
// dictionary for overridden builtins
|
||||
#if MICROPY_CAN_OVERRIDE_BUILTINS
|
||||
@ -230,6 +232,11 @@ typedef struct _mp_state_vm_t {
|
||||
// This is a global mutex used to make the VM/runtime thread-safe.
|
||||
mp_thread_mutex_t gil_mutex;
|
||||
#endif
|
||||
|
||||
#if MICROPY_OPT_MAP_LOOKUP_CACHE
|
||||
// See mp_map_lookup.
|
||||
uint8_t map_lookup_cache[MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE];
|
||||
#endif
|
||||
} mp_state_vm_t;
|
||||
|
||||
// This structure holds state that is specific to a given thread.
|
||||
|
19
py/mpz.c
19
py/mpz.c
@ -717,6 +717,7 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
|
||||
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
|
||||
if (val == 0) {
|
||||
z->neg = 0;
|
||||
z->len = 0;
|
||||
return;
|
||||
}
|
||||
@ -903,10 +904,6 @@ bool mpz_is_even(const mpz_t *z) {
|
||||
#endif
|
||||
|
||||
int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
|
||||
// to catch comparison of -0 with +0
|
||||
if (z1->len == 0 && z2->len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int cmp = (int)z2->neg - (int)z1->neg;
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
@ -1056,7 +1053,9 @@ void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
|
||||
if (dest != z) {
|
||||
mpz_set(dest, z);
|
||||
}
|
||||
dest->neg = 1 - dest->neg;
|
||||
if (dest->len) {
|
||||
dest->neg = 1 - dest->neg;
|
||||
}
|
||||
}
|
||||
|
||||
/* computes dest = ~z (= -z - 1)
|
||||
@ -1152,7 +1151,7 @@ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
|
||||
dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
}
|
||||
|
||||
dest->neg = lhs->neg;
|
||||
dest->neg = lhs->neg & !!dest->len;
|
||||
}
|
||||
|
||||
/* computes dest = lhs - rhs
|
||||
@ -1176,7 +1175,9 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
|
||||
dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if (dest->len == 0) {
|
||||
dest->neg = 0;
|
||||
} else if (neg) {
|
||||
dest->neg = 1 - lhs->neg;
|
||||
} else {
|
||||
dest->neg = lhs->neg;
|
||||
@ -1488,14 +1489,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
|
||||
|
||||
mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
|
||||
memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
|
||||
dest_quo->neg = 0;
|
||||
dest_quo->len = 0;
|
||||
mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
|
||||
mpz_set(dest_rem, lhs);
|
||||
mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
|
||||
dest_rem->neg &= !!dest_rem->len;
|
||||
|
||||
// check signs and do Python style modulo
|
||||
if (lhs->neg != rhs->neg) {
|
||||
dest_quo->neg = 1;
|
||||
dest_quo->neg = !!dest_quo->len;
|
||||
if (!mpz_is_zero(dest_rem)) {
|
||||
mpz_t mpzone;
|
||||
mpz_init_from_int(&mpzone, -1);
|
||||
|
3
py/mpz.h
3
py/mpz.h
@ -91,6 +91,7 @@ typedef int8_t mpz_dbl_dig_signed_t;
|
||||
#define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)
|
||||
|
||||
typedef struct _mpz_t {
|
||||
// Zero has neg=0, len=0. Negative zero is not allowed.
|
||||
size_t neg : 1;
|
||||
size_t fixed_dig : 1;
|
||||
size_t alloc : (8 * sizeof(size_t) - 2);
|
||||
@ -119,7 +120,7 @@ static inline bool mpz_is_zero(const mpz_t *z) {
|
||||
return z->len == 0;
|
||||
}
|
||||
static inline bool mpz_is_neg(const mpz_t *z) {
|
||||
return z->len != 0 && z->neg != 0;
|
||||
return z->neg != 0;
|
||||
}
|
||||
int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
|
||||
|
||||
|
2
py/obj.c
2
py/obj.c
@ -43,7 +43,7 @@
|
||||
#include "supervisor/shared/stack.h"
|
||||
#include "supervisor/shared/translate.h"
|
||||
|
||||
const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
|
||||
const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(mp_obj_get_type)(mp_const_obj_t o_in) {
|
||||
#if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
|
||||
|
||||
if (mp_obj_is_obj(o_in)) {
|
||||
|
1
py/obj.h
1
py/obj.h
@ -617,6 +617,7 @@ struct _mp_obj_type_t {
|
||||
//
|
||||
// dest[0] = MP_OBJ_NULL means load
|
||||
// return: for fail, do nothing
|
||||
// for fail but continue lookup in locals_dict, dest[1] = MP_OBJ_SENTINEL
|
||||
// for attr, dest[0] = value
|
||||
// for method, dest[0] = method, dest[1] = self
|
||||
//
|
||||
|
@ -39,8 +39,6 @@ typedef struct _mp_obj_fun_bc_t {
|
||||
// the following extra_args array is allocated space to take (in order):
|
||||
// - values of positional default args (if any)
|
||||
// - a single slot for default kw args dict (if it has them)
|
||||
// - a single slot for var args tuple (if it takes them)
|
||||
// - a single slot for kw args dict (if it takes them)
|
||||
mp_obj_t extra_args[];
|
||||
} mp_obj_fun_bc_t;
|
||||
|
||||
|
@ -36,6 +36,10 @@
|
||||
|
||||
#include "genhdr/moduledefs.h"
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_INIT
|
||||
STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj);
|
||||
#endif
|
||||
|
||||
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);
|
||||
@ -279,47 +283,56 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
|
||||
|
||||
MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
|
||||
|
||||
// returns MP_OBJ_NULL if not found
|
||||
mp_obj_t mp_module_get(qstr module_name) {
|
||||
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
|
||||
// lookup module
|
||||
mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
|
||||
// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
|
||||
mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name) {
|
||||
// First try loaded modules.
|
||||
mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
|
||||
|
||||
if (el == NULL) {
|
||||
// module not found, look for builtin module names
|
||||
el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
|
||||
if (el == NULL) {
|
||||
if (!elem) {
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
return mp_module_get_builtin(module_name);
|
||||
#else
|
||||
// Otherwise try builtin.
|
||||
elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
|
||||
if (!elem) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
mp_module_call_init(module_name, el->value);
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_INIT
|
||||
// If found, it's a newly loaded built-in, so init it.
|
||||
mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// module found, return it
|
||||
return el->value;
|
||||
}
|
||||
|
||||
void mp_module_register(qstr qst, mp_obj_t module) {
|
||||
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
|
||||
mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
|
||||
return elem->value;
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
// Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found
|
||||
mp_obj_t mp_module_search_umodule(const char *module_str) {
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) {
|
||||
const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i];
|
||||
const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key));
|
||||
if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) {
|
||||
return (mp_obj_t)entry->value;
|
||||
}
|
||||
|
||||
// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
|
||||
mp_obj_t mp_module_get_builtin(qstr module_name) {
|
||||
// Try builtin.
|
||||
mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
|
||||
if (!elem) {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
return MP_OBJ_NULL;
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_INIT
|
||||
// If found, it's a newly loaded built-in, so init it.
|
||||
mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
|
||||
#endif
|
||||
|
||||
return elem->value;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_INIT
|
||||
void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
|
||||
STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) {
|
||||
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
|
||||
mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
|
||||
}
|
||||
|
||||
STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) {
|
||||
// Look for __init__ and call it if it exists
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);
|
||||
|
@ -30,18 +30,9 @@
|
||||
|
||||
extern const mp_map_t mp_builtin_module_map;
|
||||
|
||||
mp_obj_t mp_module_get(qstr module_name);
|
||||
void mp_module_register(qstr qstr, mp_obj_t module);
|
||||
|
||||
mp_obj_t mp_module_search_umodule(const char *module_str);
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_INIT
|
||||
void mp_module_call_init(qstr module_name, mp_obj_t module_obj);
|
||||
#else
|
||||
static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
|
||||
(void)module_name;
|
||||
(void)module_obj;
|
||||
}
|
||||
mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name);
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
mp_obj_t mp_module_get_builtin(qstr module_name);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_OBJMODULE_H
|
||||
|
@ -616,6 +616,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
|
||||
assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));
|
||||
mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
// Note: This is fast-path'ed in the VM for the MP_BC_LOAD_ATTR operation.
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
// object member, always treated as a value
|
||||
|
38
py/parse.c
38
py/parse.c
@ -802,9 +802,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
|
||||
#endif
|
||||
|
||||
STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
|
||||
// optimise away parenthesis around an expression if possible
|
||||
// Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
|
||||
if (rule_id == RULE_atom_paren) {
|
||||
// there should be just 1 arg for this rule
|
||||
// Remove parenthesis around a single expression if possible.
|
||||
// This atom_paren rule always has a single argument, and after this
|
||||
// optimisation that argument is either NULL or testlist_comp.
|
||||
mp_parse_node_t pn = peek_result(parser, 0);
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
// need to keep parenthesis for ()
|
||||
@ -814,6 +816,34 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
|
||||
// parenthesis around a single expression, so it's just the expression
|
||||
return;
|
||||
}
|
||||
} else if (rule_id == RULE_testlist_comp) {
|
||||
// The testlist_comp rule can be the sole argument to either atom_parent
|
||||
// or atom_bracket, for (...) and [...] respectively.
|
||||
assert(num_args == 2);
|
||||
mp_parse_node_t pn = peek_result(parser, 0);
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) {
|
||||
// tuple of one item, with trailing comma
|
||||
pop_result(parser);
|
||||
--num_args;
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) {
|
||||
// tuple of many items, convert testlist_comp_3c to testlist_comp
|
||||
pop_result(parser);
|
||||
assert(pn == peek_result(parser, 0));
|
||||
pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8;
|
||||
return;
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) {
|
||||
// generator expression
|
||||
} else {
|
||||
// tuple with 2 items
|
||||
}
|
||||
} else {
|
||||
// tuple with 2 items
|
||||
}
|
||||
} else if (rule_id == RULE_testlist_comp_3c) {
|
||||
// steal first arg of outer testlist_comp rule
|
||||
++num_args;
|
||||
}
|
||||
|
||||
#if MICROPY_COMP_CONST_FOLDING
|
||||
@ -833,6 +863,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
|
||||
for (size_t i = num_args; i > 0; i--) {
|
||||
pn->nodes[i - 1] = pop_result(parser);
|
||||
}
|
||||
if (rule_id == RULE_testlist_comp_3c) {
|
||||
// need to push something non-null to replace stolen first arg of testlist_comp
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
}
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
}
|
||||
|
||||
|
@ -41,16 +41,15 @@
|
||||
#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2)
|
||||
#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2)
|
||||
|
||||
// The feature flag bits encode the compile-time config options that
|
||||
// affect the generate bytecode.
|
||||
// The feature flag bits encode the compile-time config options that affect
|
||||
// the generate bytecode. Note: position 0 is now unused
|
||||
// (formerly MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE).
|
||||
#define MPY_FEATURE_FLAGS ( \
|
||||
((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \
|
||||
| ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
|
||||
((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
|
||||
)
|
||||
// This is a version of the flags that can be configured at runtime.
|
||||
#define MPY_FEATURE_FLAGS_DYNAMIC ( \
|
||||
((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \
|
||||
| ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
|
||||
((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
|
||||
)
|
||||
|
||||
// Define the host architecture
|
||||
|
12
py/profile.c
12
py/profile.c
@ -540,9 +540,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
|
||||
instruction->qstr_opname = MP_QSTR_LOAD_NAME;
|
||||
instruction->arg = qst;
|
||||
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_GLOBAL:
|
||||
@ -550,9 +547,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
|
||||
instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL;
|
||||
instruction->arg = qst;
|
||||
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_ATTR:
|
||||
@ -560,9 +554,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
|
||||
instruction->qstr_opname = MP_QSTR_LOAD_ATTR;
|
||||
instruction->arg = qst;
|
||||
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_METHOD:
|
||||
@ -618,9 +609,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
|
||||
instruction->qstr_opname = MP_QSTR_STORE_ATTR;
|
||||
instruction->arg = qst;
|
||||
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_SUBSCR:
|
||||
|
13
py/py.mk
13
py/py.mk
@ -224,19 +224,6 @@ ifneq ($(FROZEN_MANIFEST),)
|
||||
PY_O += $(BUILD)/$(BUILD)/frozen_content.o
|
||||
endif
|
||||
|
||||
# object file for frozen files
|
||||
ifneq ($(FROZEN_DIR),)
|
||||
PY_O += $(BUILD)/frozen.o
|
||||
endif
|
||||
|
||||
# Combine old singular FROZEN_MPY_DIR with new multiple value form.
|
||||
FROZEN_MPY_DIRS += $(FROZEN_MPY_DIR)
|
||||
|
||||
# object file for frozen bytecode (frozen .mpy files)
|
||||
ifneq ($(FROZEN_MPY_DIRS),)
|
||||
PY_O += $(BUILD)/frozen_mpy.o
|
||||
endif
|
||||
|
||||
# Sources that may contain qstrings
|
||||
SRC_QSTR_IGNORE = py/nlr%
|
||||
SRC_QSTR_EMITNATIVE = py/emitn%
|
||||
|
@ -169,6 +169,12 @@ STATIC qstr qstr_add(mp_uint_t hash, mp_uint_t len, const char *q_ptr) {
|
||||
+ (sizeof(const char *) + sizeof(qstr_attr_t)) * new_pool_length;
|
||||
qstr_pool_t *pool = (qstr_pool_t *)m_malloc_maybe(pool_size, true);
|
||||
if (pool == NULL) {
|
||||
// Keep qstr_last_chunk consistent with qstr_pool_t: qstr_last_chunk is not scanned
|
||||
// at garbage collection since it's reachable from a qstr_pool_t. And the caller of
|
||||
// this function expects q_ptr to be stored in a qstr_pool_t so it can be reached
|
||||
// by the collector. If qstr_pool_t allocation failed, qstr_last_chunk needs to be
|
||||
// NULL'd. Otherwise it may become a dangling pointer at the next garbage collection.
|
||||
MP_STATE_VM(qstr_last_chunk) = NULL;
|
||||
QSTR_EXIT();
|
||||
m_malloc_fail(new_pool_length);
|
||||
}
|
||||
|
@ -60,6 +60,10 @@ Q(<string>)
|
||||
Q(<stdin>)
|
||||
Q(utf-8)
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
Q(.frozen)
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_PYSTACK
|
||||
Q(pystack exhausted)
|
||||
#endif
|
||||
|
35
py/runtime.c
35
py/runtime.c
@ -126,6 +126,15 @@ void mp_init(void) {
|
||||
sizeof(MP_STATE_VM(fs_user_mount)) - MICROPY_FATFS_NUM_PERSISTENT);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
|
||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
|
||||
#endif
|
||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_ATEXIT
|
||||
MP_STATE_VM(sys_exitfunc) = mp_const_none;
|
||||
#endif
|
||||
@ -157,7 +166,7 @@ void mp_deinit(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_name(qstr qst) {
|
||||
mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) {
|
||||
// logic: search locals, globals, builtins
|
||||
DEBUG_OP_printf("load name %s\n", qstr_str(qst));
|
||||
// If we're at the outer scope (locals == globals), dispatch to load_global right away
|
||||
@ -170,7 +179,7 @@ mp_obj_t mp_load_name(qstr qst) {
|
||||
return mp_load_global(qst);
|
||||
}
|
||||
|
||||
mp_obj_t mp_load_global(qstr qst) {
|
||||
mp_obj_t MICROPY_WRAP_MP_LOAD_GLOBAL(mp_load_global)(qstr qst) {
|
||||
// logic: search globals, builtins
|
||||
DEBUG_OP_printf("load global %s\n", qstr_str(qst));
|
||||
mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
|
||||
@ -310,7 +319,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
mp_obj_t MICROPY_WRAP_MP_BINARY_OP(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
|
||||
@ -1103,6 +1112,10 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
dest[1] = MP_OBJ_NULL;
|
||||
|
||||
// Note: the specific case of obj being an instance type is fast-path'ed in the VM
|
||||
// for the MP_BC_LOAD_ATTR opcode. Instance types handle type->attr and look up directly
|
||||
// in their member's map.
|
||||
|
||||
// get the type
|
||||
const mp_obj_type_t *type = mp_obj_get_type(obj);
|
||||
|
||||
@ -1124,7 +1137,14 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
|
||||
if (attr_fun != NULL) {
|
||||
// this type can do its own load, so call it
|
||||
attr_fun(obj, attr, dest);
|
||||
return;
|
||||
|
||||
// If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed
|
||||
// with lookups below (i.e. in locals_dict). If not, return right away.
|
||||
if (dest[1] != MP_OBJ_SENTINEL) {
|
||||
return;
|
||||
}
|
||||
// Clear the fail flag set by type->attr so it's like it never ran.
|
||||
dest[1] = MP_OBJ_NULL;
|
||||
}
|
||||
if (type->locals_dict != NULL) {
|
||||
// generic method lookup
|
||||
@ -1135,6 +1155,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
|
||||
if (elem != NULL) {
|
||||
mp_convert_member_lookup(obj, type, elem->value, dest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1426,8 +1447,10 @@ mp_obj_t mp_make_raise_obj(mp_obj_t o) {
|
||||
// create and return a new exception instance by calling o
|
||||
// TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)
|
||||
// could have const instances in ROM which we return here instead
|
||||
return mp_call_function_n_kw(o, 0, 0, NULL);
|
||||
} else if (mp_obj_is_exception_instance(o)) {
|
||||
o = mp_call_function_n_kw(o, 0, 0, NULL);
|
||||
}
|
||||
|
||||
if (mp_obj_is_exception_instance(o)) {
|
||||
// o is an instance of an exception, so use it as the exception
|
||||
return o;
|
||||
} else {
|
||||
|
@ -95,7 +95,9 @@ NORETURN void mp_arg_error_unimpl_kw(void);
|
||||
mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name);
|
||||
mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name);
|
||||
mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name);
|
||||
#endif
|
||||
mp_uint_t mp_arg_validate_length_range(mp_uint_t length, mp_uint_t min, mp_uint_t max, qstr arg_name);
|
||||
mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name);
|
||||
mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name);
|
||||
|
19
py/showbc.c
19
py/showbc.c
@ -98,8 +98,8 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
|
||||
|
||||
// raw bytecode dump
|
||||
size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell;
|
||||
mp_printf(print, "Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n",
|
||||
prelude_size, len - prelude_size);
|
||||
mp_printf(print, "Raw bytecode (code_info_size=%u, bytecode_size=%u):\n",
|
||||
(unsigned)prelude_size, (unsigned)(len - prelude_size));
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
mp_printf(print, "\n");
|
||||
@ -208,25 +208,16 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
|
||||
case MP_BC_LOAD_NAME:
|
||||
DECODE_QSTR;
|
||||
mp_printf(print, "LOAD_NAME %s", qstr_str(qst));
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
mp_printf(print, " (cache=%u)", *ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_GLOBAL:
|
||||
DECODE_QSTR;
|
||||
mp_printf(print, "LOAD_GLOBAL %s", qstr_str(qst));
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
mp_printf(print, " (cache=%u)", *ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_ATTR:
|
||||
DECODE_QSTR;
|
||||
mp_printf(print, "LOAD_ATTR %s", qstr_str(qst));
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
mp_printf(print, " (cache=%u)", *ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_METHOD:
|
||||
@ -270,9 +261,6 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
|
||||
case MP_BC_STORE_ATTR:
|
||||
DECODE_QSTR;
|
||||
mp_printf(print, "STORE_ATTR %s", qstr_str(qst));
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
mp_printf(print, " (cache=%u)", *ip++);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BC_STORE_SUBSCR:
|
||||
@ -531,7 +519,8 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
|
||||
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
|
||||
mp_printf(print, "STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
|
||||
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
|
||||
mp_printf(print, "UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
|
||||
mp_uint_t op = ip[-1] - MP_BC_UNARY_OP_MULTI;
|
||||
mp_printf(print, "UNARY_OP " UINT_FMT " %s", op, qstr_str(mp_unary_op_method_name[op]));
|
||||
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
|
||||
mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;
|
||||
mp_printf(print, "BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op]));
|
||||
|
106
py/vm.c
106
py/vm.c
@ -182,30 +182,13 @@
|
||||
#define TRACE_TICK(current_ip, current_sp, is_exception)
|
||||
#endif // MICROPY_PY_SYS_SETTRACE
|
||||
|
||||
#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
static inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) {
|
||||
size_t idx = *idx_cache;
|
||||
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (idx < map->alloc && map->table[idx].key == key) {
|
||||
elem = &map->table[idx];
|
||||
} else {
|
||||
elem = mp_map_lookup(map, key, MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
*idx_cache = (elem - &map->table[0]) & 0xff;
|
||||
}
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
#endif
|
||||
|
||||
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
|
||||
// sp points to bottom of stack which grows up
|
||||
// returns:
|
||||
// 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 state[0]
|
||||
mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
|
||||
mp_vm_return_kind_t MICROPY_WRAP_MP_EXECUTE_BYTECODE(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 */
|
||||
@ -373,84 +356,46 @@ dispatch_loop:
|
||||
goto load_check;
|
||||
}
|
||||
|
||||
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
ENTRY(MP_BC_LOAD_NAME): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_name(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
#else
|
||||
ENTRY(MP_BC_LOAD_NAME): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip);
|
||||
mp_obj_t obj;
|
||||
if (elem != NULL) {
|
||||
obj = elem->value;
|
||||
} else {
|
||||
obj = mp_load_name(qst);
|
||||
}
|
||||
PUSH(obj);
|
||||
ip++;
|
||||
DISPATCH();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
ENTRY(MP_BC_LOAD_GLOBAL): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
PUSH(mp_load_global(qst));
|
||||
DISPATCH();
|
||||
}
|
||||
#else
|
||||
ENTRY(MP_BC_LOAD_GLOBAL): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip);
|
||||
mp_obj_t obj;
|
||||
if (elem != NULL) {
|
||||
obj = elem->value;
|
||||
} else {
|
||||
obj = mp_load_global(qst);
|
||||
}
|
||||
PUSH(obj);
|
||||
ip++;
|
||||
DISPATCH();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
ENTRY(MP_BC_LOAD_ATTR): {
|
||||
FRAME_UPDATE();
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
SET_TOP(mp_load_attr(TOP(), qst));
|
||||
DISPATCH();
|
||||
}
|
||||
#else
|
||||
ENTRY(MP_BC_LOAD_ATTR): {
|
||||
FRAME_UPDATE();
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
mp_obj_t top = TOP();
|
||||
mp_obj_t obj;
|
||||
#if MICROPY_OPT_LOAD_ATTR_FAST_PATH
|
||||
// For the specific case of an instance type, it implements .attr
|
||||
// and forwards to its members map. Attribute lookups on instance
|
||||
// types are extremely common, so avoid all the other checks and
|
||||
// calls that normally happen first.
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (mp_obj_is_instance_type(mp_obj_get_type(top))) {
|
||||
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
|
||||
elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
|
||||
elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
|
||||
}
|
||||
mp_obj_t obj;
|
||||
if (elem != NULL) {
|
||||
if (elem) {
|
||||
obj = elem->value;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
obj = mp_load_attr(top, qst);
|
||||
}
|
||||
SET_TOP(obj);
|
||||
ip++;
|
||||
DISPATCH();
|
||||
}
|
||||
#endif
|
||||
|
||||
ENTRY(MP_BC_LOAD_METHOD): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
@ -506,7 +451,6 @@ dispatch_loop:
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
ENTRY(MP_BC_STORE_ATTR): {
|
||||
FRAME_UPDATE();
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
@ -515,32 +459,6 @@ dispatch_loop:
|
||||
sp -= 2;
|
||||
DISPATCH();
|
||||
}
|
||||
#else
|
||||
// This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or
|
||||
// MICROPY_PY_DESCRIPTORS enabled because if the attr exists in
|
||||
// self->members then it can't be a property or have descriptors. A
|
||||
// consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND
|
||||
// in the fast-path below, because that store could override a property.
|
||||
ENTRY(MP_BC_STORE_ATTR): {
|
||||
FRAME_UPDATE();
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
mp_map_elem_t *elem = NULL;
|
||||
mp_obj_t top = TOP();
|
||||
if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) {
|
||||
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
|
||||
elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
|
||||
}
|
||||
if (elem != NULL) {
|
||||
elem->value = sp[-1];
|
||||
} else {
|
||||
mp_store_attr(sp[0], qst, sp[-1]);
|
||||
}
|
||||
sp -= 2;
|
||||
ip++;
|
||||
DISPATCH();
|
||||
}
|
||||
#endif
|
||||
|
||||
ENTRY(MP_BC_STORE_SUBSCR):
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef likely
|
||||
@ -68,6 +69,14 @@ void *memcpy(void *dst, const void *src, size_t n) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
extern void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen);
|
||||
void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) {
|
||||
if (len > slen) {
|
||||
return NULL;
|
||||
}
|
||||
return memcpy(dest, src, len);
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) {
|
||||
// need to copy backwards
|
||||
|
@ -55,21 +55,21 @@ int pyexec_system_exit = 0;
|
||||
STATIC bool repl_display_debugging_info = 0;
|
||||
#endif
|
||||
|
||||
#define EXEC_FLAG_PRINT_EOF (1)
|
||||
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
|
||||
#define EXEC_FLAG_IS_REPL (4)
|
||||
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8)
|
||||
#define EXEC_FLAG_SOURCE_IS_VSTR (16)
|
||||
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
|
||||
#define EXEC_FLAG_SOURCE_IS_READER (64)
|
||||
#define EXEC_FLAG_SOURCE_IS_ATEXIT (128)
|
||||
#define EXEC_FLAG_PRINT_EOF (1 << 0)
|
||||
#define EXEC_FLAG_ALLOW_DEBUGGING (1 << 1)
|
||||
#define EXEC_FLAG_IS_REPL (1 << 2)
|
||||
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (1 << 3)
|
||||
#define EXEC_FLAG_SOURCE_IS_VSTR (1 << 4)
|
||||
#define EXEC_FLAG_SOURCE_IS_FILENAME (1 << 5)
|
||||
#define EXEC_FLAG_SOURCE_IS_READER (1 << 6)
|
||||
#define EXEC_FLAG_SOURCE_IS_ATEXIT (1 << 7)
|
||||
|
||||
// parses, compiles and executes the code in the lexer
|
||||
// frees the lexer before returning
|
||||
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
|
||||
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
|
||||
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
|
||||
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
|
||||
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags, pyexec_result_t *result) {
|
||||
int ret = 0;
|
||||
#if MICROPY_REPL_INFO
|
||||
uint32_t start = 0;
|
||||
@ -166,6 +166,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||
mp_hal_stdout_tx_strn("\x04", 1);
|
||||
}
|
||||
|
||||
// check for SystemExit
|
||||
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
|
||||
// at the moment, the value of SystemExit is unused
|
||||
@ -745,7 +746,7 @@ int pyexec_file(const char *filename, pyexec_result_t *result) {
|
||||
|
||||
int pyexec_file_if_exists(const char *filename, pyexec_result_t *result) {
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) {
|
||||
if (mp_find_frozen_module(filename, NULL, NULL) == MP_IMPORT_STAT_FILE) {
|
||||
return pyexec_frozen_module(filename, result);
|
||||
}
|
||||
#endif
|
||||
@ -758,7 +759,8 @@ int pyexec_file_if_exists(const char *filename, pyexec_result_t *result) {
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
|
||||
void *frozen_data;
|
||||
int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data);
|
||||
int frozen_type;
|
||||
mp_find_frozen_module(name, &frozen_type, &frozen_data);
|
||||
|
||||
switch (frozen_type) {
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
|
@ -94,6 +94,9 @@ void upytest_execute_test(const char *src) {
|
||||
gc_init(heap_start, heap_end);
|
||||
mp_init();
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
|
||||
#endif
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
|
||||
nlr_buf_t nlr;
|
||||
|
@ -1,10 +1,13 @@
|
||||
# test bignum comparisons
|
||||
|
||||
i = 1 << 65
|
||||
cases = (0, 1, -1, i, -i, i + 1, -(i + 1))
|
||||
|
||||
print(i == 0)
|
||||
print(i != 0)
|
||||
print(i < 0)
|
||||
print(i > 0)
|
||||
print(i <= 0)
|
||||
print(i >= 0)
|
||||
for lhs in cases:
|
||||
for rhs in cases:
|
||||
print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
|
||||
print("{} != {} = {}".format(lhs, rhs, lhs != rhs))
|
||||
print("{} < {} = {}".format(lhs, rhs, lhs < rhs))
|
||||
print("{} > {} = {}".format(lhs, rhs, lhs > rhs))
|
||||
print("{} <= {} = {}".format(lhs, rhs, lhs <= rhs))
|
||||
print("{} >= {} = {}".format(lhs, rhs, lhs >= rhs))
|
||||
|
@ -1,4 +1,4 @@
|
||||
# test [0,-0,1,-1] edge cases of bignum
|
||||
# test [0,1,-1] edge cases of bignum
|
||||
|
||||
import skip_if
|
||||
skip_if.no_bigint()
|
||||
@ -16,7 +16,7 @@ print([~c for c in cases])
|
||||
print([c >> 1 for c in cases])
|
||||
print([c << 1 for c in cases])
|
||||
|
||||
# comparison of 0/-0/+0
|
||||
# comparison of 0
|
||||
print(long_zero == 0)
|
||||
print(long_neg_zero == 0)
|
||||
print(long_one - 1 == 0)
|
||||
@ -29,3 +29,40 @@ print(long_neg_zero < 1)
|
||||
print(long_neg_zero < -1)
|
||||
print(long_neg_zero > 1)
|
||||
print(long_neg_zero > -1)
|
||||
|
||||
# generate zeros that involve negative numbers
|
||||
large = 1 << 70
|
||||
large_plus_one = large + 1
|
||||
zeros = (
|
||||
large - large,
|
||||
-large + large,
|
||||
large + -large,
|
||||
-(large - large),
|
||||
large - large_plus_one + 1,
|
||||
-large & (large - large),
|
||||
-large ^ -large,
|
||||
-large * (large - large),
|
||||
(large - large) // -large,
|
||||
-large // -large_plus_one,
|
||||
-(large + large) % large,
|
||||
(large + large) % -large,
|
||||
-(large + large) % -large,
|
||||
)
|
||||
print(zeros)
|
||||
|
||||
# compute arithmetic operations that may have problems with -0
|
||||
# (this checks that -0 is never generated in the zeros tuple)
|
||||
cases = (0, 1, -1) + zeros
|
||||
for lhs in cases:
|
||||
print("-{} = {}".format(lhs, -lhs))
|
||||
print("~{} = {}".format(lhs, ~lhs))
|
||||
print("{} >> 1 = {}".format(lhs, lhs >> 1))
|
||||
print("{} << 1 = {}".format(lhs, lhs << 1))
|
||||
for rhs in cases:
|
||||
print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
|
||||
print("{} + {} = {}".format(lhs, rhs, lhs + rhs))
|
||||
print("{} - {} = {}".format(lhs, rhs, lhs - rhs))
|
||||
print("{} * {} = {}".format(lhs, rhs, lhs * rhs))
|
||||
print("{} | {} = {}".format(lhs, rhs, lhs | rhs))
|
||||
print("{} & {} = {}".format(lhs, rhs, lhs & rhs))
|
||||
print("{} ^ {} = {}".format(lhs, rhs, lhs ^ rhs))
|
||||
|
@ -22,6 +22,13 @@ def foo(a, b):
|
||||
return f'{x}{y}{a}{b}'
|
||||
print(foo(7, 8))
|
||||
|
||||
# ':' character within {...} that should not be interpreted as format specifiers.
|
||||
print(f"a{[0,1,2][0:2]}")
|
||||
print(f"a{[0,15,2][0:2][-1]:04x}")
|
||||
|
||||
# Nested '{' and '}' characters.
|
||||
print(f"a{ {0,1,2}}")
|
||||
|
||||
# PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas
|
||||
# MicroPython relies on the syntax error as a result of the substitution.
|
||||
|
||||
|
39
tests/basics/subclass_native_exc_new.py
Normal file
39
tests/basics/subclass_native_exc_new.py
Normal file
@ -0,0 +1,39 @@
|
||||
# test subclassing exceptions and providing __new__
|
||||
|
||||
|
||||
class Dummy(BaseException):
|
||||
pass
|
||||
|
||||
|
||||
class GoodException(BaseException):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print("GoodException __new__")
|
||||
return Dummy(*args, **kwargs)
|
||||
|
||||
|
||||
class BadException(BaseException):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print("BadException __new__")
|
||||
return 1
|
||||
|
||||
|
||||
try:
|
||||
raise GoodException("good message")
|
||||
except BaseException as good:
|
||||
print(type(good), good.args[0])
|
||||
|
||||
try:
|
||||
raise BadException("bad message")
|
||||
except Exception as bad:
|
||||
# Should be TypeError 'exceptions must derive from BaseException'
|
||||
print(type(bad), bad.args[0])
|
||||
|
||||
try:
|
||||
|
||||
def gen():
|
||||
yield
|
||||
|
||||
gen().throw(BadException)
|
||||
except Exception as genbad:
|
||||
# Should be TypeError 'exceptions must derive from BaseException'
|
||||
print(type(genbad), genbad.args[0])
|
6
tests/basics/subclass_native_exc_new.py.exp
Normal file
6
tests/basics/subclass_native_exc_new.py.exp
Normal file
@ -0,0 +1,6 @@
|
||||
GoodException __new__
|
||||
<class 'Dummy'> good message
|
||||
BadException __new__
|
||||
<class 'TypeError'> exceptions must derive from BaseException
|
||||
BadException __new__
|
||||
<class 'TypeError'> exceptions must derive from BaseException
|
16
tests/basics/sys_path.py
Normal file
16
tests/basics/sys_path.py
Normal file
@ -0,0 +1,16 @@
|
||||
# test sys.path
|
||||
|
||||
try:
|
||||
import usys as sys
|
||||
except ImportError:
|
||||
import sys
|
||||
|
||||
# check that this script was executed from a file of the same name
|
||||
if "__file__" not in globals() or "sys_path.py" not in __file__:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
# test that sys.path[0] is the directory containing this script
|
||||
with open(sys.path[0] + "/sys_path.py") as f:
|
||||
for _ in range(4):
|
||||
print(f.readline())
|
@ -78,11 +78,11 @@ arg names:
|
||||
45 STORE_NAME g
|
||||
48 LOAD_CONST_OBJ \.\+
|
||||
50 LOAD_METHOD format
|
||||
53 LOAD_NAME b (cache=0)
|
||||
57 CALL_METHOD n=1 nkw=0
|
||||
59 STORE_NAME h
|
||||
62 LOAD_CONST_NONE
|
||||
63 RETURN_VALUE
|
||||
53 LOAD_NAME b
|
||||
56 CALL_METHOD n=1 nkw=0
|
||||
58 STORE_NAME h
|
||||
61 LOAD_CONST_NONE
|
||||
62 RETURN_VALUE
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
GC: total: \\d\+, used: \\d\+, free: \\d\+
|
||||
|
@ -15,9 +15,9 @@ def f():
|
||||
c = [1, 2]
|
||||
d = {1, 2}
|
||||
e = {}
|
||||
f = {1: 2}
|
||||
g = "a"
|
||||
h = b"a"
|
||||
f = {1:2}
|
||||
g = 'a'
|
||||
h = b'a'
|
||||
|
||||
# unary/binary ops
|
||||
i = 1
|
||||
@ -59,7 +59,7 @@ def f():
|
||||
# comprehensions
|
||||
a = (b for c in d if e)
|
||||
a = [b for c in d if e]
|
||||
a = {b: b for c in d if e}
|
||||
a = {b:b for c in d if e}
|
||||
|
||||
# function calls
|
||||
a()
|
||||
@ -108,10 +108,8 @@ def f():
|
||||
|
||||
# closed over variables
|
||||
x = 1
|
||||
|
||||
def closure():
|
||||
nonlocal x
|
||||
a = x + 1
|
||||
nonlocal x; a = x + 1
|
||||
x = 1
|
||||
del x
|
||||
|
||||
@ -128,14 +126,12 @@ def f():
|
||||
return
|
||||
return 1
|
||||
|
||||
|
||||
# function with lots of locals
|
||||
def f():
|
||||
l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = 1
|
||||
m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = m10 = 2
|
||||
l10 + m10
|
||||
|
||||
|
||||
# functions with default args
|
||||
def f(a=1):
|
||||
pass
|
||||
@ -143,19 +139,16 @@ def f(a=1):
|
||||
def f(b=2):
|
||||
return b + a
|
||||
|
||||
|
||||
# function which yields
|
||||
def f():
|
||||
yield
|
||||
yield 1
|
||||
yield from 1
|
||||
|
||||
|
||||
# class
|
||||
class Class:
|
||||
pass
|
||||
|
||||
|
||||
# delete name
|
||||
del Class
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
File cmdline/cmd_showbc.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+51 63
|
||||
\.\+63
|
||||
arg names:
|
||||
(N_STATE 3)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=167
|
||||
bc=\\d\+ line=160
|
||||
00 MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
@ -45,7 +45,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
(INIT_CELL 16)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=129
|
||||
bc=\\d\+ line=127
|
||||
00 LOAD_CONST_NONE
|
||||
01 LOAD_CONST_FALSE
|
||||
02 BINARY_OP 27 __add__
|
||||
@ -92,10 +92,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
58 BINARY_OP 27 __add__
|
||||
\\d\+ STORE_FAST 8
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ UNARY_OP 1
|
||||
\\d\+ UNARY_OP 1 __neg__
|
||||
\\d\+ STORE_FAST 9
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ STORE_FAST 10
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_DEREF 14
|
||||
@ -116,14 +116,14 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_FAST 1
|
||||
\\d\+ BINARY_OP 2 __eq__
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ UNARY_OP 3
|
||||
\\d\+ STORE_FAST 10
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_ATTR c (cache=0)
|
||||
\\d\+ LOAD_ATTR c
|
||||
\\d\+ STORE_FAST 11
|
||||
\\d\+ LOAD_FAST 11
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ STORE_ATTR c (cache=0)
|
||||
\\d\+ STORE_ATTR c
|
||||
\\d\+ LOAD_DEREF 14
|
||||
\\d\+ LOAD_CONST_SMALL_INT 0
|
||||
\\d\+ LOAD_SUBSCR
|
||||
@ -233,7 +233,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
\\d\+ LOAD_DEREF 16
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_GLOBAL y (cache=0)
|
||||
\\d\+ LOAD_GLOBAL y
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ JUMP \\d\+
|
||||
\\d\+ LOAD_DEREF 14
|
||||
@ -320,7 +320,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=136
|
||||
bc=\\d\+ line=133
|
||||
00 LOAD_CONST_SMALL_INT 1
|
||||
01 DUP_TOP
|
||||
02 STORE_FAST 0
|
||||
@ -376,7 +376,7 @@ arg names: a
|
||||
(N_EXC_STACK 0)
|
||||
(INIT_CELL 0)
|
||||
########
|
||||
bc=\\d\+ line=143
|
||||
bc=\\d\+ line=139
|
||||
00 LOAD_CONST_SMALL_INT 2
|
||||
01 BUILD_TUPLE 1
|
||||
03 LOAD_NULL
|
||||
@ -393,9 +393,9 @@ arg names:
|
||||
(N_STATE 2)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=149
|
||||
bc=3 line=150
|
||||
bc=6 line=151
|
||||
bc=0 line=144
|
||||
bc=3 line=145
|
||||
bc=6 line=146
|
||||
00 LOAD_CONST_NONE
|
||||
01 YIELD_VALUE
|
||||
02 POP_TOP
|
||||
@ -418,13 +418,13 @@ arg names:
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=13 line=156
|
||||
00 LOAD_NAME __name__ (cache=0)
|
||||
04 STORE_NAME __module__
|
||||
07 LOAD_CONST_STRING 'Class'
|
||||
10 STORE_NAME __qualname__
|
||||
13 LOAD_CONST_NONE
|
||||
14 RETURN_VALUE
|
||||
bc=12 line=150
|
||||
00 LOAD_NAME __name__
|
||||
03 STORE_NAME __module__
|
||||
06 LOAD_CONST_STRING 'Class'
|
||||
09 STORE_NAME __qualname__
|
||||
12 LOAD_CONST_NONE
|
||||
13 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
@ -433,9 +433,9 @@ arg names: self
|
||||
(N_STATE 4)
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=164
|
||||
00 LOAD_GLOBAL super (cache=0)
|
||||
\\d\+ LOAD_GLOBAL __class__ (cache=0)
|
||||
bc=0 line=157
|
||||
00 LOAD_GLOBAL super
|
||||
\\d\+ LOAD_GLOBAL __class__
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_SUPER_METHOD f
|
||||
\\d\+ CALL_METHOD n=0 nkw=0
|
||||
@ -517,7 +517,7 @@ arg names: *
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=116
|
||||
bc=\\d\+ line=114
|
||||
00 LOAD_DEREF 0
|
||||
02 LOAD_CONST_SMALL_INT 1
|
||||
03 BINARY_OP 27 __add__
|
||||
@ -536,7 +536,7 @@ arg names: * b
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
########
|
||||
bc=\\d\+ line=144
|
||||
bc=\\d\+ line=140
|
||||
00 LOAD_FAST 1
|
||||
01 LOAD_DEREF 0
|
||||
03 BINARY_OP 27 __add__
|
||||
|
@ -8,12 +8,12 @@ arg names:
|
||||
(N_EXC_STACK 0)
|
||||
bc=0 line=1
|
||||
bc=0 line=3
|
||||
00 LOAD_NAME print (cache=0)
|
||||
04 LOAD_CONST_SMALL_INT 1
|
||||
05 CALL_FUNCTION n=1 nkw=0
|
||||
07 POP_TOP
|
||||
08 LOAD_CONST_NONE
|
||||
09 RETURN_VALUE
|
||||
00 LOAD_NAME print
|
||||
03 LOAD_CONST_SMALL_INT 1
|
||||
04 CALL_FUNCTION n=1 nkw=0
|
||||
06 POP_TOP
|
||||
07 LOAD_CONST_NONE
|
||||
08 RETURN_VALUE
|
||||
1
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
|
@ -1,12 +1,13 @@
|
||||
"""
|
||||
categories: Core
|
||||
description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces
|
||||
description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings
|
||||
cause: MicroPython is optimised for code space.
|
||||
workaround: Use the + operator between literal strings when either is an f-string
|
||||
workaround: Use the + operator between literal strings when either or both are f-strings
|
||||
"""
|
||||
|
||||
x = 1
|
||||
print("aa" f"{x}")
|
||||
print(f"{x}" "ab")
|
||||
print("a{}a" f"{x}")
|
||||
print(f"{x}" "a{}b")
|
||||
x, y = 1, 2
|
||||
print("aa" f"{x}") # works
|
||||
print(f"{x}" "ab") # works
|
||||
print("a{}a" f"{x}") # fails
|
||||
print(f"{x}" "a{}b") # fails
|
||||
print(f"{x}" f"{y}") # fails
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""
|
||||
categories: Core
|
||||
description: f-strings cannot support expressions that require parsing to resolve nested braces
|
||||
description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets
|
||||
cause: MicroPython is optimised for code space.
|
||||
workaround: Only use simple expressions inside f-strings
|
||||
workaround: Always use balanced braces and brackets in expressions inside f-strings
|
||||
"""
|
||||
|
||||
f'{"hello {} world"}'
|
||||
f"{repr({})}"
|
||||
print(f'{"hello { world"}')
|
||||
print(f'{"hello ] world"}')
|
||||
|
@ -22,8 +22,9 @@ async def factorial(name, number):
|
||||
|
||||
async def task(id):
|
||||
print("start", id)
|
||||
await asyncio.sleep(0.2)
|
||||
await asyncio.sleep(0.02)
|
||||
print("end", id)
|
||||
return id
|
||||
|
||||
|
||||
async def gather_task():
|
||||
@ -36,12 +37,17 @@ async def main():
|
||||
# Simple gather with return values
|
||||
print(await asyncio.gather(factorial("A", 2), factorial("B", 3), factorial("C", 4)))
|
||||
|
||||
# Test return_exceptions, where one task is cancelled and the other finishes normally
|
||||
tasks = [asyncio.create_task(task(1)), asyncio.create_task(task(2))]
|
||||
tasks[0].cancel()
|
||||
print(await asyncio.gather(*tasks, return_exceptions=True))
|
||||
|
||||
# Cancel a multi gather
|
||||
# TODO doesn't work, Task should not forward cancellation from gather to sub-task
|
||||
# but rather CancelledError should cancel the gather directly, which will then cancel
|
||||
# all sub-tasks explicitly
|
||||
# t = asyncio.create_task(gather_task())
|
||||
# await asyncio.sleep(0.1)
|
||||
# await asyncio.sleep(0.01)
|
||||
# t.cancel()
|
||||
# await asyncio.sleep(0.01)
|
||||
|
||||
|
@ -8,3 +8,6 @@ Task B: factorial(3) = 6
|
||||
Task C: Compute factorial(4)...
|
||||
Task C: factorial(4) = 24
|
||||
[2, 6, 24]
|
||||
start 2
|
||||
end 2
|
||||
[CancelledError(), 2]
|
||||
|
@ -5,7 +5,9 @@ try:
|
||||
except ImportError:
|
||||
try:
|
||||
import socket, select
|
||||
except ImportError:
|
||||
|
||||
select.poll # Raises AttributeError for CPython implementations without poll()
|
||||
except (ImportError, AttributeError):
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
@ -1,125 +0,0 @@
|
||||
# test importing of .mpy files with native code (x64 only)
|
||||
|
||||
import sys, uio
|
||||
|
||||
try:
|
||||
uio.IOBase
|
||||
import uos
|
||||
|
||||
uos.mount
|
||||
except (ImportError, AttributeError):
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
if not (sys.platform == "linux" and sys.maxsize > 2**32):
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
|
||||
class UserFile(uio.IOBase):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.pos = 0
|
||||
|
||||
def read(self):
|
||||
return self.data
|
||||
|
||||
def readinto(self, buf):
|
||||
n = 0
|
||||
while n < len(buf) and self.pos < len(self.data):
|
||||
buf[n] = self.data[self.pos]
|
||||
n += 1
|
||||
self.pos += 1
|
||||
return n
|
||||
|
||||
def ioctl(self, req, arg):
|
||||
return 0
|
||||
|
||||
|
||||
class UserFS:
|
||||
def __init__(self, files):
|
||||
self.files = files
|
||||
|
||||
def mount(self, readonly, mksfs):
|
||||
pass
|
||||
|
||||
def umount(self):
|
||||
pass
|
||||
|
||||
def stat(self, path):
|
||||
if path in self.files:
|
||||
return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
raise OSError
|
||||
|
||||
def open(self, path, mode):
|
||||
return UserFile(self.files[path])
|
||||
|
||||
|
||||
# these are the test .mpy files
|
||||
user_files = {
|
||||
# bad architecture
|
||||
"/mod0.mpy": b"C\x05\xff\x00\x10",
|
||||
# test loading of viper and asm
|
||||
"/mod1.mpy": (
|
||||
b"C\x05\x0b\x1f\x20" # header
|
||||
b"\x20" # n bytes, bytecode
|
||||
b"\x00\x08\x02m\x02m" # prelude
|
||||
b"\x51" # LOAD_CONST_NONE
|
||||
b"\x63" # RETURN_VALUE
|
||||
b"\x00\x02" # n_obj, n_raw_code
|
||||
b"\x22" # n bytes, viper code
|
||||
b"\x00\x00\x00\x00\x00\x00" # dummy machine code
|
||||
b"\x00\x00" # qstr0
|
||||
b"\x01\x0c\x0aprint" # n_qstr, qstr0
|
||||
b"\x00\x00\x00" # scope_flags, n_obj, n_raw_code
|
||||
b"\x23" # n bytes, asm code
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00" # dummy machine code
|
||||
b"\x00\x00\x00" # scope_flags, n_pos_args, type_sig
|
||||
),
|
||||
# test loading viper with truncated data
|
||||
"/mod2.mpy": (
|
||||
b"C\x05\x0b\x1f\x20" # header
|
||||
b"\x20" # n bytes, bytecode
|
||||
b"\x00\x08\x02m\x02m" # prelude
|
||||
b"\x51" # LOAD_CONST_NONE
|
||||
b"\x63" # RETURN_VALUE
|
||||
b"\x00\x01" # n_obj, n_raw_code
|
||||
b"\x12" # n bytes(=4), viper code
|
||||
),
|
||||
# test loading viper with additional scope flags and relocation
|
||||
"/mod3.mpy": (
|
||||
b"C\x05\x0b\x1f\x20" # header
|
||||
b"\x20" # n bytes, bytecode
|
||||
b"\x00\x08\x02m\x02m" # prelude
|
||||
b"\x51" # LOAD_CONST_NONE
|
||||
b"\x63" # RETURN_VALUE
|
||||
b"\x00\x01" # n_obj, n_raw_code
|
||||
b"\x12" # n bytes(=4), viper code
|
||||
b"\x00\x00\x00\x00" # dummy machine code
|
||||
b"\x00" # n_qstr
|
||||
b"\x81\x60" # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC (0xe0 encoded over two bytes)
|
||||
b"\x00\x00" # n_obj, n_raw_code
|
||||
b"\x06rodata" # rodata, 6 bytes
|
||||
b"\x04" # bss, 4 bytes
|
||||
b"\x03\x01\x00" # dummy relocation of rodata
|
||||
),
|
||||
}
|
||||
|
||||
# create and mount a user filesystem
|
||||
uos.mount(UserFS(user_files), "/userfs")
|
||||
sys.path.append("/userfs")
|
||||
|
||||
# import .mpy files from the user filesystem
|
||||
for i in range(len(user_files)):
|
||||
mod = "mod%u" % i
|
||||
try:
|
||||
__import__(mod)
|
||||
print(mod, "OK")
|
||||
except ValueError as er:
|
||||
print(mod, "ValueError", er)
|
||||
except RuntimeError as er:
|
||||
print(mod, "RuntimeError", er)
|
||||
|
||||
# unmount and undo path addition
|
||||
uos.umount("/userfs")
|
||||
sys.path.pop()
|
@ -1,4 +0,0 @@
|
||||
mod0 ValueError incompatible native .mpy architecture
|
||||
mod1 OK
|
||||
mod2 RuntimeError Corrupt .mpy file
|
||||
mod3 OK
|
@ -1,15 +0,0 @@
|
||||
import uio
|
||||
import sys
|
||||
|
||||
try:
|
||||
uio.resource_stream
|
||||
except AttributeError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
buf = uio.resource_stream("data", "file2")
|
||||
print(buf.read())
|
||||
|
||||
# resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack
|
||||
buf = uio.resource_stream(None, sys.path[0] + "/data/file2")
|
||||
print(buf.read())
|
@ -1,2 +0,0 @@
|
||||
1234
|
||||
1234
|
@ -1,4 +1,5 @@
|
||||
# test constant optimisation
|
||||
# This test will only work when MICROPY_COMP_CONST is enabled.
|
||||
|
||||
from micropython import const
|
||||
|
||||
|
@ -48,8 +48,8 @@ class UserFS:
|
||||
# Pre-compiled examples/natmod/features0 example for various architectures, keyed
|
||||
# by the required value of sys.implementation.mpy.
|
||||
features0_file_contents = {
|
||||
# -march=x64 -mcache-lookup-bc
|
||||
0xB05: b'C\x05\x0b\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08H\x8bk(\xff\xd5H\x8d5 \x00\x00\x00I\x89\xc4H\x8b\x05.\x00\x00\x00\x0f\xb78\xffShL\x89\xe7\xff\xd5H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial \x00\x00\r \x01"\xa1\x1c\x01\x1e\xff',
|
||||
# -march=x64
|
||||
0xA05: b'C\x05\x0a\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial \x00\x00\r \x01"\xa1\x1c\x01\x1e\xff',
|
||||
# -march=armv7m
|
||||
0x1605: b"C\x05\x16\x1f \x84\x12\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\tN\tK~D\xf4X@hgi\xb8G\x05F\x07K\x07I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd6\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x01\x84\x00\x12factorial \x00\x00\r<\x01>\xa18\x01:\xff",
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ class UserFS:
|
||||
# fmt: off
|
||||
user_files = {
|
||||
# bad architecture
|
||||
'/mod0.mpy': b'C\x05\xff\x00\x10',
|
||||
'/mod0.mpy': b'C\x05\xfe\x00\x10',
|
||||
|
||||
# test loading of viper and asm
|
||||
'/mod1.mpy': (
|
||||
b'C\x05\x0b\x1f\x20' # header
|
||||
b'C\x05\x0a\x1f\x20' # header
|
||||
|
||||
b'\x20' # n bytes, bytecode
|
||||
b'\x00\x08\x02m\x02m' # prelude
|
||||
@ -78,7 +78,7 @@ user_files = {
|
||||
|
||||
# test loading viper with additional scope flags and relocation
|
||||
'/mod2.mpy': (
|
||||
b'C\x05\x0b\x1f\x20' # header
|
||||
b'C\x05\x0a\x1f\x20' # header
|
||||
|
||||
b'\x20' # n bytes, bytecode
|
||||
b'\x00\x08\x02m\x02m' # prelude
|
||||
|
20
tests/micropython/viper_subscr_multi.py
Normal file
20
tests/micropython/viper_subscr_multi.py
Normal file
@ -0,0 +1,20 @@
|
||||
# test viper with multiple subscripts in a single expression
|
||||
|
||||
|
||||
@micropython.viper
|
||||
def f1(b: ptr8):
|
||||
b[0] += b[1]
|
||||
|
||||
|
||||
@micropython.viper
|
||||
def f2(b: ptr8, i: int):
|
||||
b[0] += b[i]
|
||||
|
||||
|
||||
b = bytearray(b"\x01\x02")
|
||||
f1(b)
|
||||
print(b)
|
||||
|
||||
b = bytearray(b"\x01\x02")
|
||||
f2(b, 1)
|
||||
print(b)
|
2
tests/micropython/viper_subscr_multi.py.exp
Normal file
2
tests/micropython/viper_subscr_multi.py.exp
Normal file
@ -0,0 +1,2 @@
|
||||
bytearray(b'\x03\x02')
|
||||
bytearray(b'\x03\x02')
|
@ -54,8 +54,8 @@ except NotImplementedError:
|
||||
# str(...) with keywords not implemented
|
||||
try:
|
||||
str(b"abc", encoding="utf8")
|
||||
except NotImplementedError:
|
||||
print("NotImplementedError")
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
||||
# str.rsplit(None, n) not implemented
|
||||
try:
|
||||
|
@ -5,7 +5,7 @@ NotImplementedError
|
||||
NotImplementedError
|
||||
TypeError, ValueError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
TypeError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
|
@ -15,7 +15,7 @@ def transform_radix2(vector, inverse):
|
||||
|
||||
# Initialization
|
||||
n = len(vector)
|
||||
levels = int(math.log2(n))
|
||||
levels = int(math.log(n) / math.log(2))
|
||||
coef = (2 if inverse else -2) * cmath.pi / n
|
||||
exptable = [cmath.rect(1, i * coef) for i in range(n // 2)]
|
||||
vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation
|
||||
|
@ -112,7 +112,7 @@ def run_micropython(pyb, args, test_file, is_special=False):
|
||||
def get(required=False):
|
||||
rv = b""
|
||||
while True:
|
||||
ready = select.select([emulator], [], [], 0.02)
|
||||
ready = select.select([emulator], [], [emulator], 0.02)
|
||||
if ready[0] == [emulator]:
|
||||
rv += os.read(emulator, 1024)
|
||||
else:
|
||||
@ -150,8 +150,8 @@ def run_micropython(pyb, args, test_file, is_special=False):
|
||||
p.kill()
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
os.close(emulator)
|
||||
os.close(subterminal)
|
||||
os.close(emulator)
|
||||
else:
|
||||
output_mupy = subprocess.check_output(
|
||||
args + [test_file], stderr=subprocess.STDOUT
|
||||
@ -757,9 +757,7 @@ the last matching regex is used:
|
||||
cmd_parser.add_argument(
|
||||
"--via-mpy", action="store_true", help="compile .py files to .mpy first"
|
||||
)
|
||||
cmd_parser.add_argument(
|
||||
"--mpy-cross-flags", default="-mcache-lookup-bc", help="flags to pass to mpy-cross"
|
||||
)
|
||||
cmd_parser.add_argument("--mpy-cross-flags", default="", help="flags to pass to mpy-cross")
|
||||
cmd_parser.add_argument(
|
||||
"--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests"
|
||||
)
|
||||
@ -871,7 +869,7 @@ the last matching regex is used:
|
||||
|
||||
if not args.keep_path:
|
||||
# clear search path to make sure tests use only builtin modules and those in extmod
|
||||
os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod")
|
||||
os.environ["MICROPYPATH"] = os.pathsep + ".frozen" + os.pathsep + base_path("../extmod")
|
||||
|
||||
try:
|
||||
os.makedirs(args.result_dir, exist_ok=True)
|
||||
|
@ -89,12 +89,6 @@ try:
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
# test loading a resource from a frozen string
|
||||
import uio
|
||||
|
||||
buf = uio.resource_stream("frzstr_pkg2", "mod.py")
|
||||
print(buf.read(21))
|
||||
|
||||
# test for MP_QSTR_NULL regression
|
||||
from frzqstr import returns_NULL
|
||||
|
||||
|
@ -44,10 +44,10 @@ ime
|
||||
|
||||
utime utimeq
|
||||
|
||||
argv byteorder exc_info exit
|
||||
getsizeof implementation maxsize modules
|
||||
path platform stderr stdin
|
||||
stdout version version_info
|
||||
argv atexit byteorder exc_info
|
||||
exit getsizeof implementation maxsize
|
||||
modules path platform stderr
|
||||
stdin stdout version version_info
|
||||
ementation
|
||||
# attrtuple
|
||||
(start=1, stop=2, step=3)
|
||||
@ -165,15 +165,14 @@ cpp None
|
||||
frzstr1
|
||||
frzstr1.py
|
||||
frzmpy1
|
||||
.frozen/frzmpy1.py
|
||||
frzmpy1.py
|
||||
frzstr_pkg1.__init__
|
||||
frzstr_pkg1/__init__.py 1
|
||||
frzmpy_pkg1.__init__
|
||||
.frozen/frzmpy_pkg1/__init__.py 1
|
||||
frzmpy_pkg1/__init__.py 1
|
||||
frzstr_pkg2.mod
|
||||
1
|
||||
frzmpy_pkg2.mod
|
||||
1
|
||||
ZeroDivisionError
|
||||
b'# test frozen package'
|
||||
NULL
|
||||
|
116
tools/autobuild/build-boards.sh
Executable file
116
tools/autobuild/build-boards.sh
Executable file
@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# The functions in this file can be run independently to build boards.
|
||||
# For example:
|
||||
#
|
||||
# $ source build-boards.sh
|
||||
# $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp
|
||||
|
||||
function build_board {
|
||||
# check/get parameters
|
||||
if [ $# -lt 4 ]; then
|
||||
echo "usage: $0 <board-json-file> <fw-tag> <dest-dir> <exts...>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
board_json=$1
|
||||
fw_tag=$2
|
||||
dest_dir=$3
|
||||
shift
|
||||
shift
|
||||
shift
|
||||
|
||||
board=$(echo $board_json | awk -F '/' '{ print $2 }')
|
||||
descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
|
||||
build_dir=/tmp/micropython-build-$board
|
||||
|
||||
echo "building $descr $board"
|
||||
$MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && (
|
||||
for ext in $@; do
|
||||
dest=$dest_dir/$descr$fw_tag.$ext
|
||||
if [ -r $build_dir/firmware.$ext ]; then
|
||||
mv $build_dir/firmware.$ext $dest
|
||||
else
|
||||
# esp32 has micropython.elf and micropython.map
|
||||
mv $build_dir/micropython.$ext $dest
|
||||
fi
|
||||
done
|
||||
)
|
||||
rm -rf $build_dir
|
||||
}
|
||||
|
||||
function build_boards {
|
||||
# check/get parameters
|
||||
if [ $# -lt 4 ]; then
|
||||
echo "usage: $0 <check-file> <fw-tag> <dest-dir> <exts...>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
check_file=$1
|
||||
shift
|
||||
|
||||
# check we are in the correct directory
|
||||
if [ ! -r $check_file ]; then
|
||||
echo "must be in directory containing $check_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# build all boards that have a board.json file
|
||||
for board_json in $(find boards/ -name board.json | sort); do
|
||||
build_board $board_json $@
|
||||
done
|
||||
}
|
||||
|
||||
function build_esp32_boards {
|
||||
# check/get parameters
|
||||
if [ $# != 2 ]; then
|
||||
echo "usage: $0 <fw-tag> <dest-dir>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
fw_tag=$1
|
||||
dest_dir=$2
|
||||
|
||||
# check we are in the correct directory
|
||||
if [ ! -r modesp32.c ]; then
|
||||
echo "must be in esp32 directory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# build the boards, based on the IDF version
|
||||
for board_json in $(find boards/ -name board.json | sort); do
|
||||
mcu=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('mcu', 'unknown'))")
|
||||
if idf.py --version | grep -q v4.2; then
|
||||
if [ $mcu = esp32 ]; then
|
||||
# build standard esp32-based boards with IDF v4.2
|
||||
if echo $board_json | grep -q GENERIC; then
|
||||
# traditionally, GENERIC and GENERIC_SPIRAM boards used manifest_release.py
|
||||
MICROPY_AUTOBUILD_MAKE="$MICROPY_AUTOBUILD_MAKE FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py" build_board $board_json $fw_tag $dest_dir bin elf map
|
||||
else
|
||||
build_board $board_json $fw_tag $dest_dir bin elf map
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ $mcu != esp32 ]; then
|
||||
# build esp32-s2/s3/c3 based boards with IDF v4.4+
|
||||
build_board $board_json $fw_tag $dest_dir bin elf map
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function build_mimxrt_boards {
|
||||
build_boards modmimxrt.c $1 $2 bin hex
|
||||
}
|
||||
|
||||
function build_rp2_boards {
|
||||
build_boards modrp2.c $1 $2 uf2
|
||||
}
|
||||
|
||||
function build_samd_boards {
|
||||
build_boards samd_soc.c $1 $2 uf2
|
||||
}
|
||||
|
||||
function build_stm32_boards {
|
||||
build_boards modpyb.c $1 $2 dfu hex
|
||||
}
|
58
tools/autobuild/build-downloads.py
Executable file
58
tools/autobuild/build-downloads.py
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main(repo_path, output_path):
|
||||
boards_index = []
|
||||
board_ids = set()
|
||||
|
||||
for board_json in glob.glob(os.path.join(repo_path, "ports/*/boards/*/board.json")):
|
||||
# Relative path to the board directory (e.g. "ports/stm32/boards/PYBV11").
|
||||
board_dir = os.path.dirname(board_json)
|
||||
# Relative path to the port (e.g. "ports/stm32")
|
||||
port_dir = os.path.dirname(os.path.dirname(board_dir))
|
||||
|
||||
with open(board_json, "r") as f:
|
||||
blob = json.load(f)
|
||||
|
||||
# Use "id" if specified, otherwise default to board dir (e.g. "PYBV11").
|
||||
# We allow boards to override ID for the historical build names.
|
||||
blob["id"] = blob.get("id", os.path.basename(board_dir))
|
||||
|
||||
# Check for duplicate board IDs.
|
||||
if blob["id"] in board_ids:
|
||||
print("Duplicate board ID: '{}'".format(blob["id"]), file=sys.stderr)
|
||||
board_ids.add(blob["id"])
|
||||
|
||||
# Add in default fields.
|
||||
blob["port"] = os.path.basename(port_dir)
|
||||
blob["build"] = os.path.basename(board_dir)
|
||||
boards_index.append(blob)
|
||||
|
||||
# Create the board markdown, which is the concatenation of the
|
||||
# default "board.md" file (if exists), as well as any flashing
|
||||
# instructions.
|
||||
board_markdown = os.path.join(board_dir, "board.md")
|
||||
with open(os.path.join(output_path, blob["id"] + ".md"), "w") as f:
|
||||
if os.path.exists(board_markdown):
|
||||
with open(board_markdown, "r") as fin:
|
||||
f.write(fin.read())
|
||||
|
||||
if blob["deploy"]:
|
||||
f.write("\n\n## Installation instructions\n")
|
||||
for deploy in blob["deploy"]:
|
||||
with open(os.path.join(board_dir, deploy), "r") as fin:
|
||||
f.write(fin.read())
|
||||
|
||||
# Write the full index for the website to load.
|
||||
with open(os.path.join(output_path, "index.json"), "w") as f:
|
||||
json.dump(boards_index, f, indent=4, sort_keys=True)
|
||||
f.write("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1], sys.argv[2])
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user