diff --git a/.travis.yml b/.travis.yml index 2a5c597eb7..76aa965d2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ script: - make -C bare-arm - make -C qemu-arm test - make -C stmhal - - make -C stmhal -B MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1 + - make -C stmhal BOARD=PYBV11 MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1 - make -C stmhal BOARD=STM32F7DISC - make -C stmhal BOARD=STM32L476DISC - make -C teensy diff --git a/README.md b/README.md index 61ffce27ca..9e747e82c2 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ WARNING: this project is in beta stage and is subject to changes of the code-base, including project-wide name changes and API changes. MicroPython implements the entire Python 3.4 syntax (including exceptions, -"with", "yield from", etc., and additionally "async" keyword from Python 3.5). -The following core datatypes are provided: str (including basic Unicode -support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array, -collections.namedtuple, classes and instances. Builtin modules include sys, -time, and struct, etc. Select ports have support for _thread module -(multithreading). Note that only subset of Python 3.4 functionality -implemented for the data types and modules. +`with`, `yield from`, etc., and additionally `async`/`await` keywords from +Python 3.5). The following core datatypes are provided: `str` (including +basic Unicode support), `bytes`, `bytearray`, `tuple`, `list`, `dict`, `set`, +`frozenset`, `array.array`, `collections.namedtuple`, classes and instances. +Builtin modules include `sys`, `time`, and `struct`, etc. Select ports have +support for `_thread` module (multithreading). Note that only a subset of +Python 3 functionality is implemented for the data types and modules. See the repository www.github.com/micropython/pyboard for the MicroPython board (PyBoard), the officially supported reference electronic circuit board. diff --git a/bare-arm/main.c b/bare-arm/main.c index 99a7f926ef..938414dfe8 100644 --- a/bare-arm/main.c +++ b/bare-arm/main.c @@ -6,15 +6,12 @@ #include "py/compile.h" #include "py/runtime.h" #include "py/repl.h" +#include "py/mperrno.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - return; - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); @@ -35,7 +32,7 @@ int main(int argc, char **argv) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/cc3200/mptask.c b/cc3200/mptask.c index c7c1832edb..3c49a56035 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -98,7 +98,6 @@ OsiTaskHandle svTaskHandle; DECLARE PRIVATE DATA ******************************************************************************/ static fs_user_mount_t *sflash_vfs_fat; -static mp_vfs_mount_t sflash_vfs_mount; static const char fresh_main_py[] = "# main.py -- put your code here!\r\n"; static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" @@ -303,8 +302,6 @@ STATIC void mptask_init_sflash_filesystem (void) { // Initialise the local flash filesystem. // init the vfs object fs_user_mount_t *vfs_fat = sflash_vfs_fat; - vfs_fat->str = NULL; - vfs_fat->len = 0; vfs_fat->flags = 0; pyb_flash_init_vfs(vfs_fat); @@ -328,11 +325,16 @@ STATIC void mptask_init_sflash_filesystem (void) { mptask_create_main_py(); } } else { + fail: __fatal_error("failed to create /flash"); } // mount the flash device (there should be no other devices mounted at this point) - mp_vfs_mount_t *vfs = &sflash_vfs_mount; + // we allocate this structure on the heap because vfs->next is a root pointer + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL) { + goto fail; + } vfs->str = "/flash"; vfs->len = 6; vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 657ad461be..91fc362fdd 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -39,7 +39,7 @@ Constructors - `height` is the height of the FrameBuffer in pixels - `format` specifies the type of pixel used in the FrameBuffer; valid values are ``framebuf.MVLSB``, ``framebuf.RGB565`` - and ``framebuf.GS4_HMSB``. MVLSB is monochrome 8-bit color, + and ``framebuf.GS4_HMSB``. MVLSB is monochrome 1-bit color, RGB565 is RGB 16-bit color, and GS4_HMSB is grayscale 4-bit color. Where a color value c is passed to a method, c is a small integer with an encoding that is dependent on the format of the FrameBuffer. diff --git a/esp8266/lexerstr32.c b/esp8266/lexerstr32.c index 3fc62399e7..6fb84bb74e 100644 --- a/esp8266/lexerstr32.c +++ b/esp8266/lexerstr32.c @@ -58,10 +58,7 @@ STATIC void str32_buf_free(void *sb_in) { } mp_lexer_t *mp_lexer_new_from_str32(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) { - mp_lexer_str32_buf_t *sb = m_new_obj_maybe(mp_lexer_str32_buf_t); - if (sb == NULL) { - return NULL; - } + mp_lexer_str32_buf_t *sb = m_new_obj(mp_lexer_str32_buf_t); sb->byte_off = (uint32_t)str & 3; sb->src_cur = (uint32_t*)(str - sb->byte_off); sb->val = *sb->src_cur++ >> sb->byte_off * 8; diff --git a/esp8266/main.c b/esp8266/main.c index 0099486750..888e589704 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -32,6 +32,7 @@ #include "py/runtime0.h" #include "py/runtime.h" #include "py/stackctrl.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "py/gc.h" #include "lib/mp-readline/readline.h" @@ -64,7 +65,9 @@ STATIC void mp_reset(void) { #if MICROPY_MODULE_FROZEN pyexec_frozen_module("_boot.py"); pyexec_file("boot.py"); - pyexec_file("main.py"); + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + pyexec_file("main.py"); + } #endif } @@ -111,7 +114,7 @@ void user_init(void) { #if !MICROPY_VFS mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c index 1949305184..e3a4847835 100644 --- a/examples/embedding/hello-embed.c +++ b/examples/embedding/hello-embed.c @@ -35,9 +35,10 @@ static char heap[16384]; -mp_obj_t execute_from_lexer(mp_lexer_t *lex) { +mp_obj_t execute_from_str(const char *str) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(0/*MP_QSTR_*/, str, strlen(str), false); mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_obj_t module_fun = mp_compile(&pt, lex->source_name, MP_EMIT_OPT_NONE, false); mp_call_function_0(module_fun); @@ -58,8 +59,7 @@ int main() { mp_init(); const char str[] = "print('Hello world of easy embedding!')"; - mp_lexer_t *lex = mp_lexer_new_from_str_len(0/*MP_QSTR_*/, str, strlen(str), false); - if (execute_from_lexer(lex)) { + if (execute_from_str(str)) { printf("Error\n"); } } diff --git a/extmod/vfs.c b/extmod/vfs.c index c968345b86..3ab8261dd2 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -43,33 +43,38 @@ // Returns MP_VFS_ROOT for root dir (and then path_out is undefined) and // MP_VFS_NONE for path not found. mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) { - if (path[0] == '/' && path[1] == 0) { - return MP_VFS_ROOT; - } else if (MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { - // in root dir - if (path[0] == 0) { - return MP_VFS_ROOT; + if (*path == '/' || MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { + // an absolute path, or the current volume is root, so search root dir + bool is_abs = 0; + if (*path == '/') { + ++path; + is_abs = 1; } - } else if (*path != '/') { - // a relative path within a mounted device - *path_out = path; - return MP_STATE_VM(vfs_cur); - } - - for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { - if (strncmp(path, vfs->str, vfs->len) == 0) { - if (path[vfs->len] == '/') { - *path_out = path + vfs->len; - return vfs; - } else if (path[vfs->len] == '\0') { - *path_out = "/"; - return vfs; + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + size_t len = vfs->len - 1; + if (strncmp(path, vfs->str + 1, len) == 0) { + if (path[len] == '/') { + *path_out = path + len; + return vfs; + } else if (path[len] == '\0') { + *path_out = "/"; + return vfs; + } } } + if (*path == '\0') { + // path was "" or "/" so return virtual root + return MP_VFS_ROOT; + } + if (is_abs) { + // path began with / and was not found + return MP_VFS_NONE; + } } - // mount point not found - return MP_VFS_NONE; + // a relative path within a mounted device + *path_out = path; + return MP_STATE_VM(vfs_cur); } // Version of mp_vfs_lookup_path that takes and returns uPy string objects. diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 82dd312b8f..8cd5a4674a 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -55,8 +55,6 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; vfs->flags = FSUSER_FREE_OBJ; - vfs->str = NULL; - vfs->len = 0; vfs->fatfs.drv = vfs; // load block protocol methods diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index a5e3c604bf..7eb865254f 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -36,8 +36,6 @@ typedef struct _fs_user_mount_t { mp_obj_base_t base; - const char *str; - uint16_t len; // length of str uint16_t flags; mp_obj_t readblocks[4]; mp_obj_t writeblocks[4]; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 7efcc22f20..24c00ffba1 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -28,7 +28,7 @@ */ #include "py/mpconfig.h" -#if MICROPY_VFS +#if MICROPY_VFS && MICROPY_VFS_FAT #include #include @@ -277,4 +277,4 @@ DRESULT disk_ioctl ( } } -#endif // MICROPY_VFS +#endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 6263492cbd..edffa37c76 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -25,7 +25,7 @@ */ #include "py/mpconfig.h" -#if MICROPY_VFS +#if MICROPY_VFS && MICROPY_VFS_FAT #include #include @@ -37,10 +37,8 @@ #include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" -#if MICROPY_VFS_FAT #define mp_type_fileio fatfs_type_fileio #define mp_type_textio fatfs_type_textio -#endif extern const mp_obj_type_t mp_type_fileio; extern const mp_obj_type_t mp_type_textio; @@ -300,4 +298,4 @@ mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) return file_open(self, &mp_type_textio, arg_vals); } -#endif // MICROPY_VFS +#endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index 9509582d22..891098aa1e 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -27,7 +27,7 @@ #include #include -#include "py/nlr.h" +#include "py/runtime.h" #include "py/stream.h" #include "py/reader.h" #include "extmod/vfs.h" @@ -69,30 +69,19 @@ STATIC void mp_reader_vfs_close(void *data) { m_del_obj(mp_reader_vfs_t, reader); } -int mp_reader_new_file(mp_reader_t *reader, const char *filename) { - mp_reader_vfs_t *rf = m_new_obj_maybe(mp_reader_vfs_t); - if (rf == NULL) { - return MP_ENOMEM; - } - // TODO we really should just let this function raise a uPy exception - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); - rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); - int errcode; - rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); - nlr_pop(); - if (errcode != 0) { - return errcode; - } - } else { - return MP_ENOENT; // assume error was "file not found" +void mp_reader_new_file(mp_reader_t *reader, const char *filename) { + mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); + rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); + int errcode; + rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_OSError(errcode); } rf->pos = 0; reader->data = rf; reader->readbyte = mp_reader_vfs_readbyte; reader->close = mp_reader_vfs_close; - return 0; // success } #endif // MICROPY_READER_VFS diff --git a/lib/memzip/lexermemzip.c b/lib/memzip/lexermemzip.c index 72fe6b1c6b..6b26961bdc 100644 --- a/lib/memzip/lexermemzip.c +++ b/lib/memzip/lexermemzip.c @@ -1,6 +1,8 @@ #include #include "py/lexer.h" +#include "py/runtime.h" +#include "py/mperrno.h" #include "memzip.h" mp_lexer_t *mp_lexer_new_from_file(const char *filename) @@ -9,7 +11,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) size_t len; if (memzip_locate(filename, &data, &len) != MZ_OK) { - return NULL; + mp_raise_OSError(MP_ENOENT); } return mp_lexer_new_from_str_len(qstr_from_str(filename), (const char *)data, (mp_uint_t)len, 0); diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 0d20c19178..112cfe5925 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -52,13 +52,15 @@ STATIC bool repl_display_debugging_info = 0; #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) // 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(void *source, mp_parse_input_kind_t input_kind, int exec_flags) { +STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) { int ret = 0; uint32_t start = 0; @@ -76,8 +78,16 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, #endif { #if MICROPY_ENABLE_COMPILER + mp_lexer_t *lex; + if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { + lex = mp_lexer_new_from_file(source); + } else { + lex = (mp_lexer_t*)source; + } // source is a lexer, parse and compile the script - mp_lexer_t *lex = source; qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL); @@ -202,14 +212,9 @@ STATIC int pyexec_raw_repl_process_char(int c) { return PYEXEC_FORCED_EXIT; } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, MP_STATE_VM(repl_line)->buf, MP_STATE_VM(repl_line)->len, 0); - if (lex == NULL) { - mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04"); - } else { - int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF); - if (ret & PYEXEC_FORCED_EXIT) { - return ret; - } + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; } reset: @@ -285,14 +290,9 @@ STATIC int pyexec_friendly_repl_process_char(int c) { } exec: ; - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(MP_STATE_VM(repl_line)), vstr_len(MP_STATE_VM(repl_line)), 0); - if (lex == NULL) { - printf("MemoryError\n"); - } else { - int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); - if (ret & PYEXEC_FORCED_EXIT) { - return ret; - } + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; } input_restart: @@ -361,14 +361,9 @@ raw_repl_reset: return PYEXEC_FORCED_EXIT; } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0); - if (lex == NULL) { - printf("\x04MemoryError\n\x04"); - } else { - int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF); - if (ret & PYEXEC_FORCED_EXIT) { - return ret; - } + int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; } } } @@ -489,14 +484,9 @@ friendly_repl_reset: } } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); - if (lex == NULL) { - printf("MemoryError\n"); - } else { - ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); - if (ret & PYEXEC_FORCED_EXIT) { - return ret; - } + ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; } } } @@ -505,14 +495,7 @@ friendly_repl_reset: #endif // MICROPY_ENABLE_COMPILER int pyexec_file(const char *filename) { - mp_lexer_t *lex = mp_lexer_new_from_file(filename); - - if (lex == NULL) { - printf("could not open file '%s' for reading\n", filename); - return false; - } - - return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0); + return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME); } #if MICROPY_MODULE_FROZEN diff --git a/minimal/main.c b/minimal/main.c index 766ad6c1b4..496d925e77 100644 --- a/minimal/main.c +++ b/minimal/main.c @@ -7,18 +7,14 @@ #include "py/runtime.h" #include "py/repl.h" #include "py/gc.h" +#include "py/mperrno.h" #include "lib/utils/pyexec.h" #if MICROPY_ENABLE_COMPILER void do_str(const char *src, mp_parse_input_kind_t input_kind) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - printf("MemoryError: lexer could not allocate memory\n"); - return; - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); @@ -74,7 +70,7 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 378c013c8d..4c88c72224 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -57,14 +57,10 @@ STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) { STATIC const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) { - mp_lexer_t *lex = mp_lexer_new_from_file(file); - if (lex == NULL) { - printf("could not open file '%s' for reading\n", file); - return 1; - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_file(file); + qstr source_name; if (source_file == NULL) { source_name = lex->source_name; diff --git a/pic16bit/main.c b/pic16bit/main.c index fcc51b6617..f2a9debab1 100644 --- a/pic16bit/main.c +++ b/pic16bit/main.c @@ -33,6 +33,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mphal.h" +#include "py/mperrno.h" #include "lib/utils/pyexec.h" #include "readline.h" #include "board.h" @@ -98,7 +99,7 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { @@ -111,6 +112,7 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); void nlr_jump_fail(void *val) { + while (1); } void NORETURN __fatal_error(const char *msg) { diff --git a/py/builtinevex.c b/py/builtinevex.c index 636f869300..b0514ee994 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -136,9 +136,6 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i mp_lexer_t *lex; if (MICROPY_PY_BUILTINS_EXECFILE && parse_input_kind == MP_PARSE_SINGLE_INPUT) { lex = mp_lexer_new_from_file(str); - if (lex == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "could not open file '%s'", str)); - } parse_input_kind = MP_PARSE_FILE_INPUT; } else { lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0); diff --git a/py/builtinimport.c b/py/builtinimport.c index 0a917c6f83..96846b9636 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -131,18 +131,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d } #if MICROPY_ENABLE_COMPILER -STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) { - - if (lex == NULL) { - // we verified the file exists using stat, but lexer could still fail - if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ImportError, "module not found"); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, - "no module named '%s'", fname)); - } - } - +STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); @@ -207,7 +196,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // found the filename in the list of frozen files, then load and execute it. #if MICROPY_MODULE_FROZEN_STR if (frozen_type == MP_FROZEN_STR) { - do_load_from_lexer(module_obj, modref, file_str); + do_load_from_lexer(module_obj, modref); return; } #endif @@ -235,7 +224,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); - do_load_from_lexer(module_obj, lex, file_str); + do_load_from_lexer(module_obj, lex); return; } #endif diff --git a/py/emitnative.c b/py/emitnative.c index 9176f0a3c2..55eb6cadfc 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -385,11 +385,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2); } else if (i == 2) { ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); - } else if (i == 3) { - ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); } else { - // TODO not implemented - mp_not_implemented("more than 4 viper args"); + assert(i == 3); // should be true; max 4 args is checked above + ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); } } #endif @@ -527,9 +525,7 @@ STATIC void emit_native_end_pass(emit_t *emit) { ASM_END_PASS(emit->as); // check stack is back to zero size - if (emit->stack_size != 0) { - mp_printf(&mp_plat_print, "ERROR: stack size not back to zero; got %d\n", emit->stack_size); - } + assert(emit->stack_size == 0); if (emit->pass == MP_PASS_EMIT) { void *f = mp_asm_base_get_code(&emit->as->base); @@ -595,38 +591,9 @@ STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) { (void)source_line; } -/* -STATIC void emit_pre_raw(emit_t *emit, int stack_size_delta) { - adjust_stack(emit, stack_size_delta); - emit->last_emit_was_return_value = false; -} -*/ - // this must be called at start of emit functions STATIC void emit_native_pre(emit_t *emit) { emit->last_emit_was_return_value = false; - // settle the stack - /* - if (regs_needed != 0) { - for (int i = 0; i < emit->stack_size; i++) { - switch (emit->stack_info[i].kind) { - case STACK_VALUE: - break; - - case STACK_REG: - // TODO only push reg if in regs_needed - emit->stack_info[i].kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].data.u_reg, emit->stack_start + i); - break; - - case STACK_IMM: - // don't think we ever need to push imms for settling - //ASM_MOV_IMM_TO_LOCAL(emit->last_imm, emit->stack_start + i); - break; - } - } - } - */ } // depth==0 is top, depth==1 is before top, etc @@ -867,7 +834,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de break; default: // not handled - assert(0); + mp_not_implemented("conversion to object"); } } @@ -1011,9 +978,7 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { // do native array access. For now we just load them as any other object. /* if (emit->do_viper_types) { - // not implemented properly // load a pointer to the asciiz string? - assert(0); emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst)); } else */ @@ -1843,12 +1808,6 @@ STATIC void emit_native_pop_block(emit_t *emit) { STATIC void emit_native_pop_except(emit_t *emit) { (void)emit; - /* - emit_native_pre(emit); - emit_call(emit, MP_F_NLR_POP); - adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t))); - emit_post(emit); - */ } STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { @@ -2202,7 +2161,8 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u emit_post_top_set_vtype(emit, vtype_cast); break; default: - assert(!"TODO: convert obj to int"); + // this can happen when casting a cast: int(int) + mp_not_implemented("casting"); } } else { assert(vtype_fun == VTYPE_PYOBJ); @@ -2259,7 +2219,6 @@ STATIC void emit_native_return_value(emit_t *emit) { assert(vtype == VTYPE_PYOBJ); } emit->last_emit_was_return_value = true; - //ASM_BREAK_POINT(emit->as); // to insert a break-point for debugging ASM_EXIT(emit->as); } diff --git a/py/lexer.c b/py/lexer.c index 9dcdd19eb5..fadaee6f35 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -699,13 +699,7 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { - mp_lexer_t *lex = m_new_obj_maybe(mp_lexer_t); - - // check for memory allocation error - if (lex == NULL) { - reader.close(reader.data); - return NULL; - } + mp_lexer_t *lex = m_new_obj(mp_lexer_t); lex->source_name = src_name; lex->reader = reader; @@ -715,16 +709,9 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { lex->nested_bracket_level = 0; lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT; lex->num_indent_level = 1; - lex->indent_level = m_new_maybe(uint16_t, lex->alloc_indent_level); + lex->indent_level = m_new(uint16_t, lex->alloc_indent_level); vstr_init(&lex->vstr, 32); - // check for memory allocation error - // note: vstr_init above may fail on malloc, but so may mp_lexer_to_next below - if (lex->indent_level == NULL) { - mp_lexer_free(lex); - return NULL; - } - // store sentinel for first indentation level lex->indent_level[0] = 0; @@ -764,9 +751,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len) { mp_reader_t reader; - if (!mp_reader_new_mem(&reader, (const byte*)str, len, free_len)) { - return NULL; - } + mp_reader_new_mem(&reader, (const byte*)str, len, free_len); return mp_lexer_new(src_name, reader); } @@ -774,10 +759,7 @@ mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len mp_lexer_t *mp_lexer_new_from_file(const char *filename) { mp_reader_t reader; - int ret = mp_reader_new_file(&reader, filename); - if (ret != 0) { - return NULL; - } + mp_reader_new_file(&reader, filename); return mp_lexer_new(qstr_from_str(filename), reader); } @@ -785,10 +767,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) { mp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd) { mp_reader_t reader; - int ret = mp_reader_new_file_from_fd(&reader, fd, close_fd); - if (ret != 0) { - return NULL; - } + mp_reader_new_file_from_fd(&reader, fd, close_fd); return mp_lexer_new(filename, reader); } diff --git a/py/mkrules.mk b/py/mkrules.mk index b71450a21d..bc6389144b 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -71,12 +71,7 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h $(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) | $(HEADER_BUILD)/mpversion.h $(ECHO) "GEN $@" - $(Q)if [ "$?" = "" ]; then \ - echo "QSTR Looks like -B used, trying to emulate"; \ - $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $^ >$(HEADER_BUILD)/qstr.i.last; \ - else \ - $(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $? >$(HEADER_BUILD)/qstr.i.last; \ - fi + $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $? >$(HEADER_BUILD)/qstr.i.last; $(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last $(ECHO) "GEN $@" diff --git a/py/mpprint.c b/py/mpprint.c index 72d1c55ca0..4bc45fef4d 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -222,7 +222,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char char prefix_buf[4]; char *prefix = prefix_buf; - if (mp_obj_int_sign(x) > 0) { + if (mp_obj_int_sign(x) >= 0) { if (flags & PF_FLAG_SHOW_SIGN) { *prefix++ = '+'; } else if (flags & PF_FLAG_SPACE_SIGN) { diff --git a/py/nlrx64.c b/py/nlrx64.c index 845aac67af..c23fd8fc6a 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -61,6 +61,9 @@ unsigned int nlr_push(nlr_buf_t *nlr) { #else __asm volatile ( + #if defined(__APPLE__) || defined(__MACH__) + "pop %rbp \n" // undo function's prelude + #endif "movq (%rsp), %rax \n" // load return %rip "movq %rax, 16(%rdi) \n" // store %rip into nlr_buf "movq %rbp, 24(%rdi) \n" // store %rbp into nlr_buf @@ -70,7 +73,11 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf "movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf "movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf + #if defined(__APPLE__) || defined(__MACH__) + "jmp _nlr_push_tail \n" // do the rest in C + #else "jmp nlr_push_tail \n" // do the rest in C + #endif ); #endif diff --git a/py/objint.c b/py/objint.c index 2a7e3f3fd9..5aa6a95cc0 100644 --- a/py/objint.c +++ b/py/objint.c @@ -127,11 +127,17 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { #undef MP_FLOAT_EXP_SHIFT_I32 #endif +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef mp_longint_impl_t fmt_int_t; +#else +typedef mp_int_t fmt_int_t; +#endif + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. - char stack_buf[sizeof(mp_int_t) * 4]; + char stack_buf[sizeof(fmt_int_t) * 4]; char *buf = stack_buf; size_t buf_size = sizeof(stack_buf); size_t fmt_size; @@ -144,12 +150,6 @@ void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t } } -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG -typedef mp_longint_impl_t fmt_int_t; -#else -typedef mp_int_t fmt_int_t; -#endif - STATIC const uint8_t log_base2_floor[] = { 0, 1, 1, 2, 2, 2, 2, 3, diff --git a/py/objint_longlong.c b/py/objint_longlong.c index b798c91cdf..4ab49f337d 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -54,7 +54,17 @@ const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { - mp_not_implemented(""); + int delta = 1; + if (!big_endian) { + buf += len - 1; + delta = -1; + } + + mp_longint_impl_t value = 0; + for (; len--; buf += delta) { + value = (value << 8) | *buf; + } + return mp_obj_new_int_from_ll(value); } void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { diff --git a/py/objstr.c b/py/objstr.c index 17d06f88e8..2331004a5b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -354,7 +354,7 @@ mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: { - if (lhs_len == 0) { + if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) { return rhs_in; } if (rhs_len == 0) { diff --git a/py/persistentcode.c b/py/persistentcode.c index 5cb5117093..2a9a5b7cc0 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -225,18 +225,13 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { mp_reader_t reader; - if (!mp_reader_new_mem(&reader, buf, len, 0)) { - m_malloc_fail(BYTES_PER_WORD); // we need to raise a MemoryError - } + mp_reader_new_mem(&reader, buf, len, 0); return mp_raw_code_load(&reader); } mp_raw_code_t *mp_raw_code_load_file(const char *filename) { mp_reader_t reader; - int ret = mp_reader_new_file(&reader, filename); - if (ret != 0) { - mp_raise_OSError(ret); - } + mp_reader_new_file(&reader, filename); return mp_raw_code_load(&reader); } diff --git a/py/reader.c b/py/reader.c index d7de7aa6c4..5df45c4957 100644 --- a/py/reader.c +++ b/py/reader.c @@ -27,6 +27,7 @@ #include #include +#include "py/runtime.h" #include "py/mperrno.h" #include "py/reader.h" @@ -54,11 +55,8 @@ STATIC void mp_reader_mem_close(void *data) { m_del_obj(mp_reader_mem_t, reader); } -bool mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) { - mp_reader_mem_t *rm = m_new_obj_maybe(mp_reader_mem_t); - if (rm == NULL) { - return false; - } +void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) { + mp_reader_mem_t *rm = m_new_obj(mp_reader_mem_t); rm->free_len = free_len; rm->beg = buf; rm->cur = buf; @@ -66,7 +64,6 @@ bool mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t reader->data = rm; reader->readbyte = mp_reader_mem_readbyte; reader->close = mp_reader_mem_close; - return true; } #if MICROPY_READER_POSIX @@ -110,14 +107,8 @@ STATIC void mp_reader_posix_close(void *data) { m_del_obj(mp_reader_posix_t, reader); } -int mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { - mp_reader_posix_t *rp = m_new_obj_maybe(mp_reader_posix_t); - if (rp == NULL) { - if (close_fd) { - close(fd); - } - return MP_ENOMEM; - } +void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { + mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t); rp->close_fd = close_fd; rp->fd = fd; int n = read(rp->fd, rp->buf, sizeof(rp->buf)); @@ -125,22 +116,21 @@ int mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { if (close_fd) { close(fd); } - return errno; + mp_raise_OSError(errno); } rp->len = n; rp->pos = 0; reader->data = rp; reader->readbyte = mp_reader_posix_readbyte; reader->close = mp_reader_posix_close; - return 0; // success } -int mp_reader_new_file(mp_reader_t *reader, const char *filename) { +void mp_reader_new_file(mp_reader_t *reader, const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { - return errno; + mp_raise_OSError(errno); } - return mp_reader_new_file_from_fd(reader, fd, true); + mp_reader_new_file_from_fd(reader, fd, true); } #endif diff --git a/py/reader.h b/py/reader.h index b02d96149b..8511c72ce5 100644 --- a/py/reader.h +++ b/py/reader.h @@ -39,8 +39,8 @@ typedef struct _mp_reader_t { void (*close)(void *data); } mp_reader_t; -bool mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len); -int mp_reader_new_file(mp_reader_t *reader, const char *filename); -int mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd); +void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len); +void mp_reader_new_file(mp_reader_t *reader, const char *filename); +void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd); #endif // MICROPY_INCLUDED_PY_READER_H diff --git a/qemu-arm/Makefile b/qemu-arm/Makefile index dce739fc90..61fc243642 100644 --- a/qemu-arm/Makefile +++ b/qemu-arm/Makefile @@ -36,10 +36,12 @@ LDFLAGS= --specs=nano.specs --specs=rdimon.specs -Wl,--gc-sections -Wl,-Map=$(@: SRC_C = \ main.c \ + moduos.c \ modmachine.c \ SRC_TEST_C = \ test_main.c \ + moduos.c \ modmachine.c \ LIB_SRC_C = $(addprefix lib/,\ diff --git a/qemu-arm/main.c b/qemu-arm/main.c index aa7247b446..d5fbcd84bc 100644 --- a/qemu-arm/main.c +++ b/qemu-arm/main.c @@ -12,15 +12,12 @@ #include "py/stackctrl.h" #include "py/gc.h" #include "py/repl.h" +#include "py/mperrno.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - return; - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); @@ -47,7 +44,7 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/qemu-arm/moduos.c b/qemu-arm/moduos.c new file mode 100644 index 0000000000..dcb67396b5 --- /dev/null +++ b/qemu-arm/moduos.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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 + * 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 "extmod/vfs.h" + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + + // MicroPython extensions + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index 3452266f4b..f642c64287 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -35,6 +35,7 @@ #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_USE_INTERNAL_PRINTF (0) +#define MICROPY_VFS (1) // type definitions for the specific machine @@ -58,7 +59,11 @@ typedef long mp_off_t; #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, +// extra built-in modules to add to the list of known ones +extern const struct _mp_obj_module_t mp_module_uos; + #define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ // We need to provide a declaration/definition of alloca() diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c index 4d89930906..5c07d16076 100644 --- a/qemu-arm/test_main.c +++ b/qemu-arm/test_main.c @@ -11,7 +11,7 @@ #include "py/runtime.h" #include "py/stackctrl.h" #include "py/gc.h" -#include "py/repl.h" +#include "py/mperrno.h" #include "tinytest.h" #include "tinytest_macros.h" @@ -24,13 +24,9 @@ inline void do_str(const char *src) { gc_init(heap, (char*)heap + HEAP_SIZE); mp_init(); - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - tt_abort_msg("Lexer initialization error"); - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); @@ -80,7 +76,7 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/stmhal/main.c b/stmhal/main.c index e07f6cf8c5..8d076a08b1 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -65,7 +65,6 @@ void SystemClock_Config(void); pyb_thread_t pyb_thread_main; fs_user_mount_t fs_user_mount_flash; -mp_vfs_mount_t mp_vfs_mount_flash; void flash_error(int n) { for (int i = 0; i < n; i++) { @@ -168,8 +167,6 @@ static const char fresh_readme_txt[] = MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { // init the vfs object fs_user_mount_t *vfs_fat = &fs_user_mount_flash; - vfs_fat->str = NULL; - vfs_fat->len = 0; vfs_fat->flags = 0; pyb_flash_init_vfs(vfs_fat); @@ -219,12 +216,17 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { } else if (res == FR_OK) { // mount sucessful } else { + fail: printf("PYB: can't mount flash\n"); return false; } // mount the flash device (there should be no other devices mounted at this point) - mp_vfs_mount_t *vfs = &mp_vfs_mount_flash; + // we allocate this structure on the heap because vfs->next is a root pointer + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL) { + goto fail; + } vfs->str = "/flash"; vfs->len = 6; vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); @@ -270,8 +272,6 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) { if (vfs == NULL || vfs_fat == NULL) { break; } - vfs_fat->str = NULL; - vfs_fat->len = 0; vfs_fat->flags = FSUSER_FREE_OBJ; sdcard_init_vfs(vfs_fat, part_num); diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c index 64c1164cc8..dff781ff29 100644 --- a/stmhal/mphalport.c +++ b/stmhal/mphalport.c @@ -72,6 +72,10 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { void mp_hal_ticks_cpu_enable(void) { if (!mp_hal_ticks_cpu_enabled) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + #if defined(__CORTEX_M) && __CORTEX_M == 7 + // on Cortex-M7 we must unlock the DWT before writing to its registers + DWT->LAR = 0xc5acce55; + #endif DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; mp_hal_ticks_cpu_enabled = true; diff --git a/teensy/lexerfrozen.c b/teensy/lexerfrozen.c index 03ef800876..21e978dc79 100644 --- a/teensy/lexerfrozen.c +++ b/teensy/lexerfrozen.c @@ -1,11 +1,13 @@ #include #include "py/lexer.h" +#include "py/runtime.h" +#include "py/mperrno.h" mp_import_stat_t mp_import_stat(const char *path) { return MP_IMPORT_STAT_NO_EXIST; } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(MP_ENOENT); } diff --git a/tests/basics/builtin_property.py b/tests/basics/builtin_property.py index 403abd62f4..ff4ff073c4 100644 --- a/tests/basics/builtin_property.py +++ b/tests/basics/builtin_property.py @@ -1,4 +1,10 @@ # test builtin property +try: + property +except: + import sys + print("SKIP") + sys.exit() # create a property object explicitly property() diff --git a/tests/basics/builtin_sorted.py b/tests/basics/builtin_sorted.py index a4f71a15eb..68855b61ba 100644 --- a/tests/basics/builtin_sorted.py +++ b/tests/basics/builtin_sorted.py @@ -1,4 +1,11 @@ # test builtin sorted +try: + sorted + set +except: + import sys + print("SKIP") + sys.exit() print(sorted(set(range(100)))) print(sorted(set(range(100)), key=lambda x: x + 100*(x % 2))) diff --git a/tests/basics/bytearray_construct.py b/tests/basics/bytearray_construct.py index 1c45f6fcf5..9c8f3adaaa 100644 --- a/tests/basics/bytearray_construct.py +++ b/tests/basics/bytearray_construct.py @@ -1,12 +1,6 @@ # test construction of bytearray from different objects -from array import array - # bytes, tuple, list print(bytearray(b'123')) print(bytearray((1, 2))) print(bytearray([1, 2])) - -# arrays -print(bytearray(array('b', [1, 2]))) -print(bytearray(array('h', [0x101, 0x202]))) diff --git a/tests/basics/bytearray_construct_array.py b/tests/basics/bytearray_construct_array.py new file mode 100644 index 0000000000..6d45cafda3 --- /dev/null +++ b/tests/basics/bytearray_construct_array.py @@ -0,0 +1,11 @@ +# test construction of bytearray from different objects +try: + from array import array +except ImportError: + import sys + print("SKIP") + sys.exit() + +# arrays +print(bytearray(array('b', [1, 2]))) +print(bytearray(array('h', [0x101, 0x202]))) diff --git a/tests/basics/bytearray_construct_endian.py b/tests/basics/bytearray_construct_endian.py index dbd635c0c9..f68f9b89d1 100644 --- a/tests/basics/bytearray_construct_endian.py +++ b/tests/basics/bytearray_construct_endian.py @@ -1,6 +1,10 @@ # test construction of bytearray from different objects - -from array import array +try: + from array import array +except ImportError: + import sys + print("SKIP") + sys.exit() # arrays print(bytearray(array('h', [1, 2]))) diff --git a/tests/basics/bytes_add.py b/tests/basics/bytes_add.py index 7a887db231..ebccf0662d 100644 --- a/tests/basics/bytes_add.py +++ b/tests/basics/bytes_add.py @@ -3,9 +3,6 @@ print(b"123" + b"456") print(b"123" + bytearray(2)) -import array - -# should be byteorder-neutral -print(b"123" + array.array('h', [0x1515])) - -print(b"\x01\x02" + array.array('b', [1, 2])) +print(b"123" + b"") # RHS is empty, can be optimised +print(b"" + b"123") # LHS is empty, can be optimised +print(b"" + bytearray(1)) # LHS is empty but can't be optimised diff --git a/tests/basics/bytes_add_array.py b/tests/basics/bytes_add_array.py new file mode 100644 index 0000000000..2b8cbccef5 --- /dev/null +++ b/tests/basics/bytes_add_array.py @@ -0,0 +1,12 @@ +# test bytes + other +try: + import array +except ImportError: + import sys + print("SKIP") + sys.exit() + +# should be byteorder-neutral +print(b"123" + array.array('h', [0x1515])) + +print(b"\x01\x02" + array.array('b', [1, 2])) diff --git a/tests/basics/bytes_add_endian.py b/tests/basics/bytes_add_endian.py index 5471280d93..1bbd0f2c3a 100644 --- a/tests/basics/bytes_add_endian.py +++ b/tests/basics/bytes_add_endian.py @@ -1,5 +1,9 @@ # test bytes + other - -import array +try: + import array +except ImportError: + import sys + print("SKIP") + sys.exit() print(b"123" + array.array('i', [1])) diff --git a/tests/basics/bytes_compare2.py b/tests/basics/bytes_compare2.py index 8959da3ae7..4d5de21d21 100644 --- a/tests/basics/bytes_compare2.py +++ b/tests/basics/bytes_compare2.py @@ -3,9 +3,3 @@ print(b"123" == bytearray(b"123")) print(b'123' < bytearray(b"124")) print(b'123' > bytearray(b"122")) print(bytearray(b"23") in b"1234") - -import array - -print(array.array('b', [1, 2]) in b'\x01\x02\x03') -# CPython gives False here -#print(b"\x01\x02\x03" == array.array("B", [1, 2, 3])) diff --git a/tests/basics/bytes_compare_array.py b/tests/basics/bytes_compare_array.py new file mode 100644 index 0000000000..ad41d1d375 --- /dev/null +++ b/tests/basics/bytes_compare_array.py @@ -0,0 +1,10 @@ +try: + import array +except ImportError: + import sys + print("SKIP") + sys.exit() + +print(array.array('b', [1, 2]) in b'\x01\x02\x03') +# CPython gives False here +#print(b"\x01\x02\x03" == array.array("B", [1, 2, 3])) diff --git a/tests/basics/bytes_construct.py b/tests/basics/bytes_construct.py index 1647387675..0d638c08f2 100644 --- a/tests/basics/bytes_construct.py +++ b/tests/basics/bytes_construct.py @@ -1,16 +1,10 @@ # test construction of bytes from different objects -from array import array - # tuple, list, bytearray print(bytes((1, 2))) print(bytes([1, 2])) print(bytes(bytearray(4))) -# arrays -print(bytes(array('b', [1, 2]))) -print(bytes(array('h', [0x101, 0x202]))) - # constructor value out of range try: bytes([-1]) diff --git a/tests/basics/bytes_construct_array.py b/tests/basics/bytes_construct_array.py new file mode 100644 index 0000000000..72c2d0c585 --- /dev/null +++ b/tests/basics/bytes_construct_array.py @@ -0,0 +1,11 @@ +# test construction of bytes from different objects +try: + from array import array +except ImportError: + import sys + print("SKIP") + sys.exit() + +# arrays +print(bytes(array('b', [1, 2]))) +print(bytes(array('h', [0x101, 0x202]))) diff --git a/tests/basics/bytes_construct_endian.py b/tests/basics/bytes_construct_endian.py index 1912f63a4d..77e0eaaa56 100644 --- a/tests/basics/bytes_construct_endian.py +++ b/tests/basics/bytes_construct_endian.py @@ -1,6 +1,11 @@ # test construction of bytes from different objects -from array import array +try: + from array import array +except ImportError: + import sys + print("SKIP") + sys.exit() # arrays print(bytes(array('h', [1, 2]))) diff --git a/tests/basics/dict_fromkeys.py b/tests/basics/dict_fromkeys.py index 118d0ffd95..7b11319a23 100644 --- a/tests/basics/dict_fromkeys.py +++ b/tests/basics/dict_fromkeys.py @@ -7,8 +7,3 @@ d = dict.fromkeys([1, 2, 3, 4], 42) l = list(d.values()) l.sort() print(l) - -# argument to fromkeys has no __len__ -d = dict.fromkeys(reversed(range(1))) -#d = dict.fromkeys((x for x in range(1))) -print(d) diff --git a/tests/basics/dict_fromkeys2.py b/tests/basics/dict_fromkeys2.py new file mode 100644 index 0000000000..7ea0cc5b36 --- /dev/null +++ b/tests/basics/dict_fromkeys2.py @@ -0,0 +1,11 @@ +try: + reversed +except: + import sys + print("SKIP") + sys.exit() + +# argument to fromkeys has no __len__ +d = dict.fromkeys(reversed(range(1))) +#d = dict.fromkeys((x for x in range(1))) +print(d) diff --git a/tests/basics/fun_error.py b/tests/basics/fun_error.py index 305b249111..367fe0b7fa 100644 --- a/tests/basics/fun_error.py +++ b/tests/basics/fun_error.py @@ -27,8 +27,5 @@ test_exc("[].sort(1)", TypeError) # function with keyword args given extra keyword args test_exc("[].sort(noexist=1)", TypeError) -# function with keyword args not given a specific keyword arg -test_exc("enumerate()", TypeError) - # kw given for positional, but a different positional is missing test_exc("def f(x, y): pass\nf(x=1)", TypeError) diff --git a/tests/basics/fun_error2.py b/tests/basics/fun_error2.py new file mode 100644 index 0000000000..c4d2c0b64d --- /dev/null +++ b/tests/basics/fun_error2.py @@ -0,0 +1,19 @@ +# test errors from bad function calls +try: + enumerate +except: + print("SKIP") + import sys + sys.exit() + +def test_exc(code, exc): + try: + exec(code) + print("no exception") + except exc: + print("right exception") + except: + print("wrong exception") + +# function with keyword args not given a specific keyword arg +test_exc("enumerate()", TypeError) diff --git a/tests/basics/string_format2.py b/tests/basics/string_format2.py index e211535be4..881ff4f804 100644 --- a/tests/basics/string_format2.py +++ b/tests/basics/string_format2.py @@ -1,6 +1,6 @@ # comprehensive functionality test for {} format string -int_tests = False # these take a while, and some give wrong results +int_tests = False # these take a while char_tests = True str_tests = True diff --git a/tests/basics/string_format_modulo.py b/tests/basics/string_format_modulo.py index f00502457e..77bbcfbe36 100644 --- a/tests/basics/string_format_modulo.py +++ b/tests/basics/string_format_modulo.py @@ -33,38 +33,6 @@ print("%c" % 48) print("%c" % 'a') print("%10s" % 'abc') print("%-10s" % 'abc') -print("%d" % 10) -print("%+d" % 10) -print("% d" % 10) -print("%d" % -10) -print("%d" % True) -print("%i" % -10) -print("%i" % True) -print("%u" % -10) -print("%u" % True) -print("%x" % 18) -print("%o" % 18) -print("%X" % 18) -print("%#x" % 18) -print("%#X" % 18) -print("%#6o" % 18) -print("%#6x" % 18) -print("%#06x" % 18) - -print("%*d" % (5, 10)) -print("%*.*d" % (2, 2, 20)) -print("%*.*d" % (5, 8, 20)) - -print(">%8.4d<" % -12) -print(">% 8.4d<" % -12) -print(">%+8.4d<" % 12) -print(">%+8.4d<" % -12) -print(">%08.4d<" % -12) -print(">%08.4d<" % 12) -print(">%-8.4d<" % -12) -print(">%-08.4d<" % -12) -print(">%-+08.4d<" % -12) -print(">%-+08.4d<" % 12) # Should be able to print dicts; in this case they aren't used # to lookup keywords in formats like %(foo)s diff --git a/tests/basics/string_format_modulo_int.py b/tests/basics/string_format_modulo_int.py new file mode 100644 index 0000000000..d1f29db220 --- /dev/null +++ b/tests/basics/string_format_modulo_int.py @@ -0,0 +1,41 @@ +# test string modulo formatting with int values + +# basic cases +print("%d" % 10) +print("%+d" % 10) +print("% d" % 10) +print("%d" % -10) +print("%d" % True) +print("%i" % -10) +print("%i" % True) +print("%u" % -10) +print("%u" % True) +print("%x" % 18) +print("%o" % 18) +print("%X" % 18) +print("%#x" % 18) +print("%#X" % 18) +print("%#6o" % 18) +print("%#6x" % 18) +print("%#06x" % 18) + +# with * +print("%*d" % (5, 10)) +print("%*.*d" % (2, 2, 20)) +print("%*.*d" % (5, 8, 20)) + +# precision +for val in (-12, 12): + print(">%8.4d<" % val) + print(">% 8.4d<" % val) + print(">%+8.4d<" % val) + print(">%08.4d<" % val) + print(">%-8.4d<" % val) + print(">%-08.4d<" % val) + print(">%-+08.4d<" % val) + +# test + option with various amount of padding +for pad in ('', ' ', '0'): + for n in (1, 2, 3): + for val in (-1, 0, 1): + print(('%+' + pad + str(n) + 'd') % val) diff --git a/tests/basics/struct_micropython.py b/tests/basics/struct_micropython.py index e3b0ea5086..53306dad67 100644 --- a/tests/basics/struct_micropython.py +++ b/tests/basics/struct_micropython.py @@ -18,3 +18,16 @@ o = A() s = struct.pack(" 1: pass") +# unknown type +test("@micropython.viper\ndef f(x:unknown_type): pass") + +# too many arguments +test("@micropython.viper\ndef f(a, b, c, d, e): pass") + # local used before type known test(""" @micropython.viper @@ -49,6 +55,9 @@ test("@micropython.viper\ndef f(): 1[x]") # can't store test("@micropython.viper\ndef f(): 1[0] = 1") test("@micropython.viper\ndef f(): 1[x] = 1") +test("@micropython.viper\ndef f(x:int): x[0] = x") +test("@micropython.viper\ndef f(x:ptr32): x[0] = None") +test("@micropython.viper\ndef f(x:ptr32): x[x] = None") # must raise an object test("@micropython.viper\ndef f(): raise 1") @@ -57,3 +66,16 @@ test("@micropython.viper\ndef f(): raise 1") test("@micropython.viper\ndef f(x:int): +x") test("@micropython.viper\ndef f(x:int): -x") test("@micropython.viper\ndef f(x:int): ~x") + +# binary op not implemented +test("@micropython.viper\ndef f(x:int): res = x in x") + +# yield (from) not implemented +test("@micropython.viper\ndef f(): yield") +test("@micropython.viper\ndef f(): yield from f") + +# passing a ptr to a Python function not implemented +test("@micropython.viper\ndef f(): print(ptr(1))") + +# cast of a casting identifier not implemented +test("@micropython.viper\ndef f(): int(int)") diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index 1afcd4bdbe..96be5a5902 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -1,5 +1,7 @@ SyntaxError('parameter annotation must be an identifier',) SyntaxError('return annotation must be an identifier',) +ViperTypeError("unknown type 'unknown_type'",) +ViperTypeError("Viper functions don't currently support more than 4 arguments",) ViperTypeError("local 'x' used before type known",) ViperTypeError("local 'x' has type 'int' but source is 'object'",) ViperTypeError("can't implicitly convert 'ptr' to 'bool'",) @@ -9,7 +11,15 @@ ViperTypeError("can't load from 'int'",) ViperTypeError("can't load from 'int'",) ViperTypeError("can't store to 'int'",) ViperTypeError("can't store to 'int'",) +ViperTypeError("can't store to 'int'",) +ViperTypeError("can't store 'None'",) +ViperTypeError("can't store 'None'",) ViperTypeError('must raise an object',) ViperTypeError('unary op __pos__ not implemented',) ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) +ViperTypeError('binary op __contains__ not implemented',) +NotImplementedError('native yield',) +NotImplementedError('native yield from',) +NotImplementedError('conversion to object',) +NotImplementedError('casting',) diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 8e5d586a9e..31074ab016 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -1,7 +1,12 @@ # tests for things that are not implemented, or have non-compliant behaviour -import array -import ustruct +try: + import array + import ustruct +except ImportError: + import sys + print("SKIP") + sys.exit() # when super can't find self try: diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 30a732106c..b833a79816 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -1,8 +1,13 @@ -try: - import uio as io -except ImportError: - import io import sys +try: + try: + import uio as io + except ImportError: + import io +except ImportError: + print("SKIP") + sys.exit() + if hasattr(sys, 'print_exception'): print_exception = sys.print_exception else: diff --git a/tests/misc/recursive_data.py b/tests/misc/recursive_data.py index 0de93acb89..3830189453 100644 --- a/tests/misc/recursive_data.py +++ b/tests/misc/recursive_data.py @@ -1,5 +1,10 @@ # This tests that printing recursive data structure doesn't lead to segfault. -import uio as io +try: + import uio as io +except ImportError: + import sys + print("SKIP") + sys.exit() l = [1, 2, 3, None] l[-1] = l diff --git a/tests/misc/recursive_iternext.py b/tests/misc/recursive_iternext.py index 025fa425b5..d90f177168 100644 --- a/tests/misc/recursive_iternext.py +++ b/tests/misc/recursive_iternext.py @@ -1,4 +1,14 @@ # This tests that recursion with iternext doesn't lead to segfault. +try: + enumerate + filter + map + max + zip +except: + import sys + print("SKIP") + sys.exit() # We need to pick an N that is large enough to hit the recursion # limit, but not too large that we run out of heap memory. diff --git a/tests/run-tests b/tests/run-tests index bacaebea81..b1bb7dd846 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -209,7 +209,7 @@ def run_tests(pyb, tests, args): # Check if arbitrary-precision integers are supported, and skip such tests if it's not native = run_micropython(pyb, args, 'feature_check/int_big.py') - if native == b'CRASH': + if native != b'1000000000000000000000000000000000000000000000\n': skip_int_big = True # Check if set type (and set literals) is supported, and skip such tests if it's not @@ -261,7 +261,7 @@ def run_tests(pyb, tests, args): if pyb is not None: skip_tests.add('basics/exception_chain.py') # warning is not printed skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead - skip_tests.add('float/float2int_doubleprec.py') # requires double precision floating point to work + skip_tests.add('float/float2int_doubleprec_intbig.py') # requires double precision floating point to work skip_tests.add('micropython/meminfo.py') # output is very different to PC output skip_tests.add('extmod/machine_mem.py') # raw memory access not supported diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index ac59971a50..32117aba44 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -43,6 +43,9 @@ Warning: test ? +1e+00 +1e+00 +# binary +122 +456 0123456789 b'0123456789' 7300 7300 diff --git a/unix/coverage.c b/unix/coverage.c index 5b0c8d7a06..ca236c4303 100644 --- a/unix/coverage.c +++ b/unix/coverage.c @@ -10,6 +10,7 @@ #include "py/emit.h" #include "py/formatfloat.h" #include "py/stream.h" +#include "py/binary.h" #if defined(MICROPY_UNIX_COVERAGE) @@ -278,6 +279,19 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%s\n", buf2); } + // binary + { + mp_printf(&mp_plat_print, "# binary\n"); + + // call function with float and double typecodes + float far[1]; + double dar[1]; + mp_binary_set_val_array_from_int('f', far, 0, 123); + mp_printf(&mp_plat_print, "%.0f\n", (double)far[0]); + mp_binary_set_val_array_from_int('d', dar, 0, 456); + mp_printf(&mp_plat_print, "%.0lf\n", dar[0]); + } + mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t); s->base.type = &mp_type_stest_fileio; s->buf = NULL; diff --git a/unix/main.c b/unix/main.c index d916cdeb88..01ebdce175 100644 --- a/unix/main.c +++ b/unix/main.c @@ -90,19 +90,33 @@ STATIC int handle_uncaught_exception(mp_obj_base_t *exc) { return 1; } +#define LEX_SRC_STR (1) +#define LEX_SRC_VSTR (2) +#define LEX_SRC_FILENAME (3) +#define LEX_SRC_STDIN (4) + // Returns standard error codes: 0 for success, 1 for all other errors, // except if FORCED_EXIT bit is set then script raised SystemExit and the // value of the exit is in the lower 8 bits of the return value -STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { - if (lex == NULL) { - printf("MemoryError: lexer could not allocate memory\n"); - return 1; - } - +STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) { mp_hal_set_interrupt_char(CHAR_CTRL_C); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + // create lexer based on source kind + mp_lexer_t *lex; + if (source_kind == LEX_SRC_STR) { + const char *line = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); + } else if (source_kind == LEX_SRC_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false); + } else if (source_kind == LEX_SRC_FILENAME) { + lex = mp_lexer_new_from_file((const char*)source); + } else { // LEX_SRC_STDIN + lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); + } + qstr source_name = lex->source_name; #if MICROPY_PY___FILE__ @@ -240,8 +254,7 @@ STATIC int do_repl(void) { mp_hal_stdio_mode_orig(); - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, false); - ret = execute_from_lexer(lex, parse_input_kind, true); + ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); if (ret & FORCED_EXIT) { return ret; } @@ -268,8 +281,7 @@ STATIC int do_repl(void) { line = line3; } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); - int ret = execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true); + int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); if (ret & FORCED_EXIT) { return ret; } @@ -280,13 +292,11 @@ STATIC int do_repl(void) { } STATIC int do_file(const char *file) { - mp_lexer_t *lex = mp_lexer_new_from_file(file); - return execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); } STATIC int do_str(const char *str) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, str, strlen(str), false); - return execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false); } STATIC int usage(char **argv) { @@ -585,8 +595,7 @@ MP_NOINLINE int main_(int argc, char **argv) { ret = do_repl(); prompt_write_history(); } else { - mp_lexer_t *lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); - ret = execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + ret = execute_from_lexer(LEX_SRC_STDIN, NULL, MP_PARSE_FILE_INPUT, false); } } diff --git a/zephyr/Makefile b/zephyr/Makefile index 3779765fb5..7a0d052989 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -5,17 +5,10 @@ # recursively Makefile.zephyr to build complete application binary # using Zephyr build system. # +# To build a "minimal" configuration, use "make-minimal" wrapper. BOARD ?= qemu_x86 -ifeq ($(MAKECMDGOALS), minimal) -# For minimal, CONF_FILE must be overriden early due to $(Z_EXPORTS) target -CONF_FILE = prj_minimal.conf -else CONF_FILE = prj.conf -endif -# Zephyr 1.5.0 -#OUTDIR_PREFIX = -# Zephyr 1.6.0 OUTDIR_PREFIX = $(BOARD) # Default heap size is 16KB, which is on conservative side, to let @@ -42,6 +35,7 @@ INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os SRC_C = main.c \ help.c \ modutime.c \ + modzephyr.c \ modmachine.c \ machine_pin.c \ uart_core.c \ @@ -65,7 +59,7 @@ include ../py/mkrules.mk $(Z_EXPORTS): $(CONF_FILE) $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports -GENERIC_TARGETS = all zephyr qemu qemugdb flash debug +GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug KCONFIG_TARGETS = \ initconfig config nconfig menuconfig xconfig gconfig \ oldconfig silentoldconfig defconfig savedefconfig \ @@ -87,12 +81,6 @@ $(Z_SYSGEN_H): rm -f $(LIBMICROPYTHON) -$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) -minimal: - $(MAKE) BOARD=$(BOARD) CONF_FILE=prj_minimal.conf CFLAGS_EXTRA='-DMP_CONFIGFILE=""' FROZEN_DIR= - -qemu-minimal: - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=prj_minimal.conf QEMU_NET=0 run - # Clean Zephyr things too clean: z_clean @@ -101,5 +89,4 @@ z_clean: .PHONY: prj.conf prj.conf: prj_base.conf - cat $< >$@ - if [ -f prj_$(BOARD).conf ]; then cat prj_$(BOARD).conf >>$@; fi + $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ diff --git a/zephyr/README.md b/zephyr/README.md index 6e9e5d8492..4fbf3d4019 100644 --- a/zephyr/README.md +++ b/zephyr/README.md @@ -98,17 +98,17 @@ below 128KB, as long as Zephyr project is committed to maintain stable minimal size of their kernel (which they appear to be). Note that at such size, there is no support for any Zephyr features beyond REPL over UART, and only very minimal set of builtin Python modules. Thus, this build -is more suitable for code size control and quick demonstrations even on +is more suitable for code size control and quick demonstrations on smaller systems. It's also suitable for careful enabling of features one -by one to achieve needed functionality and code size. This is in contrast -to the "default" build, which may get more and more features enabled by -default over time. +by one to achieve needed functionality and code size. This is in a +contrast to the "default" build, which may get more and more features +enabled over time. To make a minimal build: - make BOARD= minimal + ./make-minimal BOARD= To run a minimal build in QEMU without requiring TAP networking setup run the following after you built image with the previous command: - make BOARD= qemu-minimal + ./make-minimal BOARD= qemu diff --git a/zephyr/main.c b/zephyr/main.c index d6980ad295..1f8589a6c9 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -44,14 +44,9 @@ #include "lib/mp-readline/readline.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - if (lex == NULL) { - printf("MemoryError: lexer could not allocate memory\n"); - return; - } - nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); @@ -130,7 +125,7 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - return NULL; + mp_raise_OSError(ENOENT); } mp_import_stat_t mp_import_stat(const char *path) { @@ -142,10 +137,7 @@ mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); -void nlr_jump_fail(void *val) { -} - -void NORETURN __fatal_error(const char *msg) { +NORETURN void nlr_jump_fail(void *val) { while (1); } diff --git a/zephyr/make-minimal b/zephyr/make-minimal new file mode 100755 index 0000000000..1fc143e4d6 --- /dev/null +++ b/zephyr/make-minimal @@ -0,0 +1,16 @@ +#!/bin/sh +# +# This is a wrapper for make to build a "minimal" Zephyr port. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-minimal BOARD=qemu_cortex_m3 +# ./make-minimal BOARD=qemu_cortex_m3 run +# + +make \ + CONF_FILE=prj_minimal.conf \ + CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ + FROZEN_DIR= \ + QEMU_NET=0 \ + "$@" diff --git a/zephyr/makeprj.py b/zephyr/makeprj.py new file mode 100644 index 0000000000..239c877cd6 --- /dev/null +++ b/zephyr/makeprj.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import sys +import os +import hashlib + + +def hash_file(fname): + if not os.path.exists(fname): + return b"" + hasher = hashlib.md5() + with open(fname, "rb") as f: + hasher.update(f.read()) + return hasher.digest() + + +old_digest = hash_file(sys.argv[3]) + +with open(sys.argv[3] + ".tmp", "wb") as f: + f.write(open(sys.argv[1], "rb").read()) + if os.path.exists(sys.argv[2]): + f.write(open(sys.argv[2], "rb").read()) + +new_digest = hash_file(sys.argv[3] + ".tmp") + +if new_digest != old_digest: + print("Replacing") + os.rename(sys.argv[3] + ".tmp", sys.argv[3]) +else: + os.remove(sys.argv[3] + ".tmp") diff --git a/zephyr/modzephyr.c b/zephyr/modzephyr.c new file mode 100644 index 0000000000..4bac5c970f --- /dev/null +++ b/zephyr/modzephyr.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * 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/mpconfig.h" +#if MICROPY_PY_ZEPHYR + +#include + +#include "py/runtime.h" + +STATIC mp_obj_t mod_is_preempt_thread(void) { + return mp_obj_new_bool(k_is_preempt_thread()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_is_preempt_thread_obj, mod_is_preempt_thread); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr) }, + { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_zephyr = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_ZEPHYR diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 2cd5ffcecc..e1e85df9cd 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -60,6 +60,7 @@ #define MICROPY_PY_STRUCT (0) #define MICROPY_PY_UTIME (1) #define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_ZEPHYR (1) #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) @@ -100,6 +101,7 @@ typedef long mp_off_t; extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_time; +extern const struct _mp_obj_module_t mp_module_zephyr; #if MICROPY_PY_UTIME #define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, @@ -107,9 +109,16 @@ extern const struct _mp_obj_module_t mp_module_time; #define MICROPY_PY_UTIME_DEF #endif +#if MICROPY_PY_ZEPHYR +#define MICROPY_PY_ZEPHYR_DEF { MP_ROM_QSTR(MP_QSTR_zephyr), MP_ROM_PTR(&mp_module_zephyr) }, +#else +#define MICROPY_PY_ZEPHYR_DEF +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ MICROPY_PY_UTIME_DEF \ + MICROPY_PY_ZEPHYR_DEF \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_OBJ_NEW_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \