diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtin.h | 1 | ||||
-rw-r--r-- | py/builtinimport.c | 83 | ||||
-rw-r--r-- | py/compile.c | 2 | ||||
-rw-r--r-- | py/emitglue.c | 2 | ||||
-rw-r--r-- | py/frozenmod.c | 37 | ||||
-rw-r--r-- | py/frozenmod.h | 1 | ||||
-rw-r--r-- | py/gc.c | 14 | ||||
-rw-r--r-- | py/lexer.c | 4 | ||||
-rw-r--r-- | py/makeqstrdata.py | 2 | ||||
-rw-r--r-- | py/map.c | 2 | ||||
-rw-r--r-- | py/modio.c | 14 | ||||
-rw-r--r-- | py/modmath.c | 5 | ||||
-rw-r--r-- | py/modstruct.c | 25 | ||||
-rw-r--r-- | py/moduerrno.c | 105 | ||||
-rw-r--r-- | py/mpconfig.h | 20 | ||||
-rw-r--r-- | py/mperrno.h | 143 | ||||
-rw-r--r-- | py/mphal.h | 17 | ||||
-rw-r--r-- | py/mpz.c | 67 | ||||
-rw-r--r-- | py/obj.c | 2 | ||||
-rw-r--r-- | py/obj.h | 4 | ||||
-rw-r--r-- | py/objdict.c | 2 | ||||
-rw-r--r-- | py/objexcept.c | 11 | ||||
-rw-r--r-- | py/objfloat.c | 8 | ||||
-rw-r--r-- | py/objint_mpz.c | 14 | ||||
-rw-r--r-- | py/objmodule.c | 3 | ||||
-rw-r--r-- | py/objnamedtuple.c | 5 | ||||
-rw-r--r-- | py/objstr.c | 83 | ||||
-rw-r--r-- | py/objstr.h | 1 | ||||
-rw-r--r-- | py/objstringio.c | 1 | ||||
-rw-r--r-- | py/objstrunicode.c | 3 | ||||
-rw-r--r-- | py/parse.c | 5 | ||||
-rw-r--r-- | py/py.mk | 3 | ||||
-rw-r--r-- | py/repl.c | 13 | ||||
-rw-r--r-- | py/runtime.c | 30 | ||||
-rw-r--r-- | py/stream.c | 111 | ||||
-rw-r--r-- | py/stream.h | 14 | ||||
-rw-r--r-- | py/vmentrytable.h | 2 | ||||
-rw-r--r-- | py/vstr.c | 10 |
38 files changed, 684 insertions, 185 deletions
diff --git a/py/builtin.h b/py/builtin.h index 9d6e424091..5d79d2835e 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -98,6 +98,7 @@ extern const mp_obj_module_t mp_module_gc; extern const mp_obj_dict_t mp_module_builtins_globals; // extmod modules +extern const mp_obj_module_t mp_module_uerrno; extern const mp_obj_module_t mp_module_uctypes; extern const mp_obj_module_t mp_module_uzlib; extern const mp_obj_module_t mp_module_ujson; diff --git a/py/builtinimport.c b/py/builtinimport.c index 0e4dce6430..d3670858e5 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -60,22 +60,34 @@ 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) { + #if MICROPY_MODULE_FROZEN + mp_import_stat_t st = mp_frozen_stat(path); + if (st != MP_IMPORT_STAT_NO_EXIST) { + return st; + } + #endif + return mp_import_stat(path); +} + STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { - mp_import_stat_t stat = mp_import_stat(vstr_null_terminated_str(path)); + mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); if (stat == MP_IMPORT_STAT_DIR) { return stat; } vstr_add_str(path, ".py"); - stat = mp_import_stat(vstr_null_terminated_str(path)); + stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } #if MICROPY_PERSISTENT_CODE_LOAD vstr_ins_byte(path, path->len - 2, 'm'); - stat = mp_import_stat(vstr_null_terminated_str(path)); + stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } @@ -182,10 +194,37 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { #endif STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { - #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER + #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER char *file_str = vstr_null_terminated_str(file); #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 = mp_find_frozen_module(file_str, file->len, &modref); + #endif + + // 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. + #if MICROPY_MODULE_FROZEN_STR + if (frozen_type == MP_FROZEN_STR) { + do_load_from_lexer(module_obj, modref, file_str); + return; + } + #endif + + // If we support frozen mpy modules and we found a corresponding file (and + // 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); + return; + } + #endif + + // 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. #if MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); @@ -194,15 +233,18 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { } #endif + // If we can compile scripts then load the file and compile and execute it. #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); do_load_from_lexer(module_obj, lex, file_str); + return; } - #else + #endif + + // If we get here then the file was not frozen and we can't compile scripts. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "script compilation not supported")); - #endif } STATIC void chop_component(const char *start, const char **end) { @@ -340,33 +382,6 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } DEBUG_printf("Module not yet loaded\n"); - #if MICROPY_MODULE_FROZEN - void *frozen_data; - int frozen_type = mp_find_frozen_module(mod_str, mod_len, &frozen_data); - if (frozen_type != MP_FROZEN_NONE) { - module_obj = mp_obj_new_module(module_name_qstr); - // 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). - // TODO: Duplicated below too. - if (fromtuple == mp_const_false) { - 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_MODULE_FROZEN_STR - if (frozen_type == MP_FROZEN_STR) { - do_load_from_lexer(module_obj, frozen_data, mod_str); - } - #endif - #if MICROPY_MODULE_FROZEN_MPY - if (frozen_type == MP_FROZEN_MPY) { - do_execute_raw_code(module_obj, frozen_data); - } - #endif - return module_obj; - } - #endif - uint last = 0; VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) module_obj = MP_OBJ_NULL; @@ -445,7 +460,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); - if (mp_import_stat(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { + if (mp_import_stat_any(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { diff --git a/py/compile.c b/py/compile.c index d40d8a1ff5..df6dab063c 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2649,7 +2649,7 @@ STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) } typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*); -STATIC compile_function_t compile_function[] = { +STATIC const compile_function_t compile_function[] = { #define nc NULL #define c(f) compile_##f #define DEF_RULE(rule, comp, kind, ...) comp, diff --git a/py/emitglue.c b/py/emitglue.c index b710371177..59bca781ef 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -382,7 +382,7 @@ mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { // here we define mp_raw_code_load_file depending on the port // TODO abstract this away properly -#if defined(__i386__) || defined(__x86_64__) || (defined(__arm__) && (defined(__unix__))) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || (defined(__arm__) && (defined(__unix__))) // unix file reader #include <sys/stat.h> diff --git a/py/frozenmod.c b/py/frozenmod.c index 18beb0f8e4..660167eed4 100644 --- a/py/frozenmod.c +++ b/py/frozenmod.c @@ -85,6 +85,43 @@ STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) { #if MICROPY_MODULE_FROZEN +STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) { + size_t len = strlen(str); + + 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] == '/') { + return MP_IMPORT_STAT_DIR; + } + } + name += l + 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 MICROPY_MODULE_FROZEN_STR mp_lexer_t *lex = mp_find_frozen_str(str, len); diff --git a/py/frozenmod.h b/py/frozenmod.h index a1638d2293..f08cb5e321 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -31,3 +31,4 @@ enum { }; int mp_find_frozen_module(const char *str, size_t len, void **data); +mp_import_stat_t mp_frozen_stat(const char *str); @@ -693,11 +693,8 @@ void gc_dump_alloc_table(void) { } // print header for new line of blocks // (the cast to uint32_t is for 16-bit ports) - #if EXTENSIVE_HEAP_PROFILING + //mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff)); - #else - mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); - #endif } int c = ' '; switch (ATB_GET_KIND(bl)) { @@ -734,6 +731,13 @@ void gc_dump_alloc_table(void) { if (*ptr == &mp_type_tuple) { c = 'T'; } else if (*ptr == &mp_type_list) { c = 'L'; } else if (*ptr == &mp_type_dict) { c = 'D'; } + else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) { c = 'S'; } + #if MICROPY_PY_BUILTINS_BYTEARRAY + else if (*ptr == &mp_type_bytearray) { c = 'A'; } + #endif + #if MICROPY_PY_ARRAY + else if (*ptr == &mp_type_array) { c = 'A'; } + #endif #if MICROPY_PY_BUILTINS_FLOAT else if (*ptr == &mp_type_float) { c = 'F'; } #endif @@ -761,7 +765,7 @@ void gc_dump_alloc_table(void) { } break; } - case AT_TAIL: c = 't'; break; + case AT_TAIL: c = '='; break; case AT_MARK: c = 'm'; break; } mp_printf(&mp_plat_print, "%c", c); diff --git a/py/lexer.c b/py/lexer.c index 1639740d34..820f91be78 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -190,7 +190,7 @@ STATIC void indent_pop(mp_lexer_t *lex) { // c<op> = continue with <op>, if this opchar matches then continue matching // this means if the start of two ops are the same then they are equal til the last char -STATIC const char *tok_enc = +STATIC const char *const tok_enc = "()[]{},:;@~" // singles "<e=c<e=" // < <= << <<= ">e=c>e=" // > >= >> >>= @@ -227,7 +227,7 @@ STATIC const uint8_t tok_enc_kind[] = { }; // must have the same order as enum in lexer.h -STATIC const char *tok_kw[] = { +STATIC const char *const tok_kw[] = { "False", "None", "True", diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index c00ec1eb28..8a3136b1f1 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -116,7 +116,7 @@ def parse_input_headers(infiles): def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): qhash = compute_hash(qstr, cfg_bytes_hash) - if all(32 <= ord(c) <= 126 and c != '\\' for c in qstr): + if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): # qstr is all printable ASCII so render it as-is (for easier debugging) qlen = len(qstr) qdata = qstr @@ -49,7 +49,7 @@ const mp_map_t mp_const_empty_map = { // 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 // prime. The latter sizes are prime and increase at an increasing rate. -STATIC uint16_t hash_allocation_sizes[] = { +STATIC const uint16_t hash_allocation_sizes[] = { 0, 2, 4, 6, 8, 10, 12, // +2 17, 23, 29, 37, 47, 59, 73, // *1.25 97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33 diff --git a/py/modio.c b/py/modio.c index 423315081f..2fbe6bc1e1 100644 --- a/py/modio.c +++ b/py/modio.c @@ -78,10 +78,13 @@ STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t si memcpy(self->buf + self->len, buf, rem); buf = (byte*)buf + rem; size -= rem; - mp_uint_t out_sz = mp_stream_writeall(self->stream, self->buf, self->alloc, errcode); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); + if (*errcode != 0) { return MP_STREAM_ERROR; } + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->alloc); self->len = 0; } @@ -93,9 +96,12 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { if (self->len != 0) { int err; - mp_uint_t out_sz = mp_stream_writeall(self->stream, self->buf, self->len, &err); + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->len); self->len = 0; - if (out_sz == MP_STREAM_ERROR) { + if (err != 0) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); } } diff --git a/py/modmath.c b/py/modmath.c index 6abf8ab3e9..54262f6115 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -31,6 +31,11 @@ #include <math.h> +// M_PI is not part of the math.h standard and may not be defined +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + /// \module math - mathematical functions /// /// The `math` module provides some basic mathematical funtions for diff --git a/py/modstruct.c b/py/modstruct.c index cd32097388..2016add17e 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -103,29 +103,24 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { char fmt_type = get_fmt_type(&fmt); mp_uint_t size; for (size = 0; *fmt; fmt++) { - mp_uint_t align = 1; mp_uint_t cnt = 1; if (unichar_isdigit(*fmt)) { cnt = get_fmt_num(&fmt); } - mp_uint_t sz = 0; if (*fmt == 's') { - sz = cnt; - cnt = 1; - } - - while (cnt--) { - // If we already have size for 's' case, don't set it again + size += cnt; + } else { + mp_uint_t align; + size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); if (sz == 0) { - sz = (mp_uint_t)mp_binary_get_size(fmt_type, *fmt, &align); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "unsupported format")); + } + while (cnt--) { + // Apply alignment + size = (size + align - 1) & ~(align - 1); + size += sz; } - // TODO - assert(sz != (mp_uint_t)-1); - // Apply alignment - size = (size + align - 1) & ~(align - 1); - size += sz; - sz = 0; } } return MP_OBJ_NEW_SMALL_INT(size); diff --git a/py/moduerrno.c b/py/moduerrno.c new file mode 100644 index 0000000000..343b29ba08 --- /dev/null +++ b/py/moduerrno.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 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 <assert.h> +#include <string.h> + +#include "py/obj.h" +#include "py/mperrno.h" + +#if MICROPY_PY_UERRNO + +// This list could be defined per port in mpconfigport.h to tailor it to a +// specific port's needs. But for now we have a common list. +#define ERRNO_LIST \ + X(EPERM) \ + X(ENOENT) \ + X(EIO) \ + X(EBADF) \ + X(EAGAIN) \ + X(ENOMEM) \ + X(EACCES) \ + X(EEXIST) \ + X(ENODEV) \ + X(EISDIR) \ + X(EINVAL) \ + X(EOPNOTSUPP) \ + X(EADDRINUSE) \ + X(ECONNABORTED) \ + X(ECONNRESET) \ + X(ENOBUFS) \ + X(ENOTCONN) \ + X(ETIMEDOUT) \ + X(ECONNREFUSED) \ + X(EHOSTUNREACH) \ + X(EALREADY) \ + X(EINPROGRESS) \ + +STATIC const mp_rom_map_elem_t errorcode_table[] = { + #define X(e) { MP_ROM_INT(MP_ ## e), MP_ROM_QSTR(MP_QSTR_## e) }, + ERRNO_LIST + #undef X +}; + +STATIC const mp_obj_dict_t errorcode_dict = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 0, // keys are integers + .is_fixed = 1, + .is_ordered = 1, + .used = MP_ARRAY_SIZE(errorcode_table), + .alloc = MP_ARRAY_SIZE(errorcode_table), + .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)errorcode_table, + }, +}; + +STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) }, + { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) }, + + #define X(e) { MP_ROM_QSTR(MP_QSTR_## e), MP_ROM_INT(MP_ ## e) }, + ERRNO_LIST + #undef X +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table); + +const mp_obj_module_t mp_module_uerrno = { + .base = { &mp_type_module }, + .name = MP_QSTR_uerrno, + .globals = (mp_obj_dict_t*)&mp_module_uerrno_globals, +}; + +qstr mp_errno_to_str(mp_obj_t errno_val) { + mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP); + if (elem == NULL) { + return MP_QSTR_NULL; + } else { + return MP_OBJ_QSTR_VALUE(elem->value); + } +} + +#endif //MICROPY_PY_UERRNO diff --git a/py/mpconfig.h b/py/mpconfig.h index 42ef19b72c..084fc246f5 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -555,6 +555,11 @@ typedef double mp_float_t; #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) #endif +// Whether to use internally defined errno's (otherwise system provided ones) +#ifndef MICROPY_USE_INTERNAL_ERRNO +#define MICROPY_USE_INTERNAL_ERRNO (0) +#endif + // Support for user-space VFS mount (selected ports) #ifndef MICROPY_FSUSERMOUNT #define MICROPY_FSUSERMOUNT (0) @@ -584,6 +589,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_STR_UNICODE (0) #endif +// Whether str.center() method provided +#ifndef MICROPY_PY_BUILTINS_STR_CENTER +#define MICROPY_PY_BUILTINS_STR_CENTER (0) +#endif + // Whether str.splitlines() method provided #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES #define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) @@ -809,6 +819,11 @@ typedef double mp_float_t; #define MICROPY_PY_SYS_STDIO_BUFFER (0) #endif +// Whether to provide "uerrno" module +#ifndef MICROPY_PY_UERRNO +#define MICROPY_PY_UERRNO (0) +#endif + // Extended modules #ifndef MICROPY_PY_UCTYPES @@ -852,6 +867,11 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE (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 diff --git a/py/mperrno.h b/py/mperrno.h new file mode 100644 index 0000000000..4d092de452 --- /dev/null +++ b/py/mperrno.h @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 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. + */ + +#ifndef __MICROPY_INCLUDED_PY_MPERRNO_H__ +#define __MICROPY_INCLUDED_PY_MPERRNO_H__ + +#if MICROPY_USE_INTERNAL_ERRNO + +// MP_Exxx errno's are defined directly as numeric values +// (Linux constants are used as a reference) + +#define MP_EPERM (1) // Operation not permitted +#define MP_ENOENT (2) // No such file or directory +#define MP_ESRCH (3) // No such process +#define MP_EINTR (4) // Interrupted system call +#define MP_EIO (5) // I/O error +#define MP_ENXIO (6) // No such device or address +#define MP_E2BIG (7) // Argument list too long +#define MP_ENOEXEC (8) // Exec format error +#define MP_EBADF (9) // Bad file number +#define MP_ECHILD (10) // No child processes +#define MP_EAGAIN (11) // Try again +#define MP_ENOMEM (12) // Out of memory +#define MP_EACCES (13) // Permission denied +#define MP_EFAULT (14) // Bad address +#define MP_ENOTBLK (15) // Block device required +#define MP_EBUSY (16) // Device or resource busy +#define MP_EEXIST (17) // File exists +#define MP_EXDEV (18) // Cross-device link +#define MP_ENODEV (19) // No such device +#define MP_ENOTDIR (20) // Not a directory +#define MP_EISDIR (21) // Is a directory +#define MP_EINVAL (22) // Invalid argument +#define MP_ENFILE (23) // File table overflow +#define MP_EMFILE (24) // Too many open files +#define MP_ENOTTY (25) // Not a typewriter +#define MP_ETXTBSY (26) // Text file busy +#define MP_EFBIG (27) // File too large +#define MP_ENOSPC (28) // No space left on device +#define MP_ESPIPE (29) // Illegal seek +#define MP_EROFS (30) // Read-only file system +#define MP_EMLINK (31) // Too many links +#define MP_EPIPE (32) // Broken pipe +#define MP_EDOM (33) // Math argument out of domain of func +#define MP_ERANGE (34) // Math result not representable +#define MP_EWOULDBLOCK MP_EAGAIN // Operation would block +#define MP_EOPNOTSUPP (95) // Operation not supported on transport endpoint +#define MP_EAFNOSUPPORT (97) // Address family not supported by protocol +#define MP_EADDRINUSE (98) // Address already in use +#define MP_ECONNABORTED (103) // Software caused connection abort +#define MP_ECONNRESET (104) // Connection reset by peer +#define MP_ENOBUFS (105) // No buffer space available +#define MP_ENOTCONN (107) // Transport endpoint is not connected +#define MP_ETIMEDOUT (110) // Connection timed out +#define MP_ECONNREFUSED (111) // Connection refused +#define MP_EHOSTUNREACH (113) // No route to host +#define MP_EALREADY (114) // Operation already in progress +#define MP_EINPROGRESS (115) // Operation now in progress + +#else + +// MP_Exxx errno's are defined in terms of system supplied ones + +#include <errno.h> + +#define MP_EPERM EPERM +#define MP_ENOENT ENOENT +#define MP_ESRCH ESRCH +#define MP_EINTR EINTR +#define MP_EIO EIO +#define MP_ENXIO ENXIO +#define MP_E2BIG E2BIG +#define MP_ENOEXEC ENOEXEC +#define MP_EBADF EBADF +#define MP_ECHILD ECHILD +#define MP_EAGAIN EAGAIN +#define MP_ENOMEM ENOMEM +#define MP_EACCES EACCES +#define MP_EFAULT EFAULT +#define MP_ENOTBLK ENOTBLK +#define MP_EBUSY EBUSY +#define MP_EEXIST EEXIST +#define MP_EXDEV EXDEV +#define MP_ENODEV ENODEV +#define MP_ENOTDIR ENOTDIR +#define MP_EISDIR EISDIR +#define MP_EINVAL EINVAL +#define MP_ENFILE ENFILE +#define MP_EMFILE EMFILE +#define MP_ENOTTY ENOTTY +#define MP_ETXTBSY ETXTBSY +#define MP_EFBIG EFBIG +#define MP_ENOSPC ENOSPC +#define MP_ESPIPE ESPIPE +#define MP_EROFS EROFS +#define MP_EMLINK EMLINK +#define MP_EPIPE EPIPE +#define MP_EDOM EDOM +#define MP_ERANGE ERANGE +#define MP_EWOULDBLOCK EAGAIN +#define MP_EOPNOTSUPP EOPNOTSUPP +#define MP_EAFNOSUPPORT EAFNOSUPPORT +#define MP_EADDRINUSE EADDRINUSE +#define MP_ECONNABORTED ECONNABORTED +#define MP_ECONNRESET ECONNRESET +#define MP_ENOBUFS ENOBUFS +#define MP_ENOTCONN ENOTCONN +#define MP_ETIMEDOUT ETIMEDOUT +#define MP_ECONNREFUSED ECONNREFUSED +#define MP_EHOSTUNREACH EHOSTUNREACH +#define MP_EALREADY EALREADY +#define MP_EINPROGRESS EINPROGRESS + +#endif + +#if MICROPY_PY_UERRNO +qstr mp_errno_to_str(mp_obj_t errno_val); +#endif + +#endif // __MICROPY_INCLUDED_PY_MPERRNO_H__ diff --git a/py/mphal.h b/py/mphal.h index a0b642fc98..aacd02ebd8 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -54,8 +54,25 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len); void mp_hal_delay_ms(mp_uint_t ms); #endif +#ifndef mp_hal_delay_us +void mp_hal_delay_us(mp_uint_t us); +#endif + #ifndef mp_hal_ticks_ms mp_uint_t mp_hal_ticks_ms(void); #endif +#ifndef mp_hal_ticks_us +mp_uint_t mp_hal_ticks_us(void); +#endif + +// If port HAL didn't define its own pin API, use generic +// "virtual pin" API from the core. +#ifndef mp_hal_pin_obj_t +#define mp_hal_pin_obj_t mp_obj_t +#define mp_hal_get_pin_obj(pin) (pin) +#define mp_hal_pin_read(pin) mp_virtual_pin_read(pin) +#define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v) +#endif + #endif // __MICROPY_INCLUDED_PY_MPHAL_H__ @@ -454,10 +454,8 @@ STATIC mp_uint_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mpz_d assumes num_dig has enough memory to be extended by 1 digit assumes quo_dig has enough memory (as many digits as num) assumes quo_dig is filled with zeros - modifies den_dig memory, but restors it to original state at end */ - -STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) { +STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, const mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) { mpz_dig_t *orig_num_dig = num_dig; mpz_dig_t *orig_quo_dig = quo_dig; mpz_dig_t norm_shift = 0; @@ -478,6 +476,11 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, } } + // We need to normalise the denominator (leading bit of leading digit is 1) + // so that the division routine works. Since the denominator memory is + // read-only we do the normalisation on the fly, each time a digit of the + // denominator is needed. We need to know is how many bits to shift by. + // count number of leading zeros in leading digit of denominator { mpz_dig_t d = den_dig[den_len - 1]; @@ -487,13 +490,6 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, } } - // normalise denomenator (leading bit of leading digit is 1) - for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) { - mpz_dig_t d = *den; - *den = ((d << norm_shift) | carry) & DIG_MASK; - carry = d >> (DIG_SIZE - norm_shift); - } - // now need to shift numerator by same amount as denominator // first, increase length of numerator in case we need more room to shift num_dig[*num_len] = 0; @@ -501,11 +497,14 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) { mpz_dig_t n = *num; *num = ((n << norm_shift) | carry) & DIG_MASK; - carry = n >> (DIG_SIZE - norm_shift); + carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift); } // cache the leading digit of the denominator - lead_den_digit = den_dig[den_len - 1]; + lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift; + if (den_len >= 2) { + lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift); + } // point num_dig to last digit in numerator num_dig += *num_len - 1; @@ -540,10 +539,13 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // round up). if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) { + const mpz_dig_t *d = den_dig; + mpz_dbl_dig_t d_norm = 0; mpz_dbl_dig_signed_t borrow = 0; - for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) { - borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)*d; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 *n = borrow & DIG_MASK; borrow >>= DIG_SIZE; } @@ -553,9 +555,12 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // adjust quotient if it is too big for (; borrow != 0; --quo) { + d = den_dig; + d_norm = 0; mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) { - carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); *n = carry & DIG_MASK; carry >>= DIG_SIZE; } @@ -566,10 +571,13 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, borrow += carry; } } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2 + const mpz_dig_t *d = den_dig; + mpz_dbl_dig_t d_norm = 0; mpz_dbl_dig_t borrow = 0; - for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) { - mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)(*d); + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); if (x >= *n || *n - x <= borrow) { borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n; *n = (-borrow) & DIG_MASK; @@ -590,9 +598,12 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // adjust quotient if it is too big for (; borrow != 0; --quo) { + d = den_dig; + d_norm = 0; mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) { - carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); *n = carry & DIG_MASK; carry >>= DIG_SIZE; } @@ -614,18 +625,11 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, --(*num_len); } - // unnormalise denomenator - for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) { - mpz_dig_t d = *den; - *den = ((d >> norm_shift) | carry) & DIG_MASK; - carry = d << (DIG_SIZE - norm_shift); - } - // unnormalise numerator (remainder now) for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) { mpz_dig_t n = *num; *num = ((n >> norm_shift) | carry) & DIG_MASK; - carry = n << (DIG_SIZE - norm_shift); + carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift); } // strip trailing zeros @@ -1506,11 +1510,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m dest_quo->len = 0; mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary? mpz_set(dest_rem, lhs); - //rhs->dig[rhs->len] = 0; mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len); + // check signs and do Python style modulo if (lhs->neg != rhs->neg) { dest_quo->neg = 1; + if (!mpz_is_zero(dest_rem)) { + mpz_t mpzone; mpz_init_from_int(&mpzone, -1); + mpz_add_inpl(dest_quo, dest_quo, &mpzone); + mpz_add_inpl(dest_rem, dest_rem, rhs); + } } } @@ -317,6 +317,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { #endif #endif +// note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); @@ -333,6 +334,7 @@ void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { } } +// note: returned value in *items may point to the interior of a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { mp_uint_t seq_len; mp_obj_get_array(o, &seq_len, items); @@ -651,8 +651,8 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); -void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items); -void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items); +void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items); // *items may point inside a GC block +void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items); // *items may point inside a GC block mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_id(mp_obj_t o_in); mp_obj_t mp_obj_len(mp_obj_t o_in); diff --git a/py/objdict.c b/py/objdict.c index cc1f502d0f..04da2bf624 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -414,7 +414,7 @@ typedef enum _mp_dict_view_kind_t { MP_DICT_VIEW_VALUES, } mp_dict_view_kind_t; -STATIC char *mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; +STATIC const char *const mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; typedef struct _mp_obj_dict_view_it_t { mp_obj_base_t base; diff --git a/py/objexcept.c b/py/objexcept.c index adf17b08d0..9ccc9288c9 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -36,6 +36,7 @@ #include "py/objtype.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/mperrno.h" // Instance of MemoryError exception - needed by mp_malloc_fail const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; @@ -107,6 +108,16 @@ STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr mp_print_str(print, ""); return; } else if (o->args->len == 1) { + #if MICROPY_PY_UERRNO + // try to provide a nice OSError error message + if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { + qstr qst = mp_errno_to_str(o->args->items[0]); + if (qst != MP_QSTR_NULL) { + mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); + return; + } + } + #endif mp_obj_print_helper(print, o->args->items[0], PRINT_STR); return; } diff --git a/py/objfloat.c b/py/objfloat.c index aa37f9ab2d..85b8b13861 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -41,6 +41,14 @@ #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D +// M_E and M_PI are not part of the math.h standard and may not be defined +#ifndef M_E +#define M_E (2.7182818284590452354) +#endif +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index dc083827cc..3a30eb9d9b 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -239,12 +239,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); - if (zlhs->neg != zrhs->neg) { - if (!mpz_is_zero(&rem)) { - mpz_t mpzone; mpz_init_from_int(&mpzone, -1); - mpz_add_inpl(&res->mpz, &res->mpz, &mpzone); - } - } mpz_deinit(&rem); break; } @@ -256,10 +250,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); - // Check signs and do Python style modulo - if (zlhs->neg != zrhs->neg) { - mpz_add_inpl(&res->mpz, &res->mpz, zrhs); - } break; } @@ -303,10 +293,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mp_obj_int_t *quo = mp_obj_int_new_mpz(); mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs); - // Check signs and do Python style modulo - if (zlhs->neg != zrhs->neg) { - mpz_add_inpl(&res->mpz, &res->mpz, zrhs); - } mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; return mp_obj_new_tuple(2, tuple); } diff --git a/py/objmodule.c b/py/objmodule.c index 8c3cb85e67..c7cb644488 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -163,6 +163,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { // extmod modules +#if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) }, +#endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 76dc9a1fc9..38cda1ad75 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -165,10 +165,7 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { fields_in = mp_obj_str_split(1, &fields_in); } #endif - if (!MP_OBJ_IS_TYPE(fields_in, &mp_type_list)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "list required")); - } - mp_obj_list_get(fields_in, &n_fields, &fields); + mp_obj_get_array(fields_in, &n_fields, &fields); return mp_obj_new_namedtuple_type(name, n_fields, fields); } MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); diff --git a/py/objstr.c b/py/objstr.c index d0d090b995..e51c371f7b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -464,9 +464,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { return mp_obj_new_str_from_vstr(self_type, &vstr); } -enum {SPLIT = 0, KEEP = 1, SPLITLINES = 2}; - -STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args, int type) { +mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_int_t splits = -1; mp_obj_t sep = mp_const_none; @@ -527,13 +525,7 @@ STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args } s++; } - mp_uint_t sub_len = s - start; - if (MP_LIKELY(!(sub_len == 0 && s == top && (type && SPLITLINES)))) { - if (start + sub_len != top && (type & KEEP)) { - sub_len++; - } - mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); - } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); if (s >= top) { break; } @@ -547,25 +539,49 @@ STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args return res; } -mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { - return str_split_internal(n_args, args, SPLIT); -} - #if MICROPY_PY_BUILTINS_STR_SPLITLINES STATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_keepends }; static const mp_arg_t allowed_args[] = { { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args - struct { - mp_arg_val_t keepends; - } args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]); + mp_obj_t res = mp_obj_new_list(0, NULL); + + GET_STR_DATA_LEN(pos_args[0], s, len); + const byte *top = s + len; + + while (s < top) { + const byte *start = s; + size_t match = 0; + while (s < top) { + if (*s == '\n') { + match = 1; + break; + } else if (*s == '\r') { + if (s[1] == '\n') { + match = 2; + } else { + match = 1; + } + break; + } + s++; + } + size_t sub_len = s - start; + if (args[ARG_keepends].u_bool) { + sub_len += match; + } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); + s += match; + } - mp_obj_t new_args[2] = {pos_args[0], MP_OBJ_NEW_QSTR(MP_QSTR__0x0a_)}; - return str_split_internal(2, new_args, SPLITLINES | (args.keepends.u_bool ? KEEP : 0)); + return res; } #endif @@ -801,6 +817,23 @@ STATIC mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) { return str_uni_strip(RSTRIP, n_args, args); } +#if MICROPY_PY_BUILTINS_STR_CENTER +STATIC mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) { + GET_STR_DATA_LEN(str_in, str, str_len); + mp_uint_t width = mp_obj_get_int(width_in); + if (str_len >= width) { + return str_in; + } + + vstr_t vstr; + vstr_init_len(&vstr, width); + memset(vstr.buf, ' ', width); + int left = (width - str_len) / 2; + memcpy(vstr.buf + left, str, str_len); + return mp_obj_new_str_from_vstr(mp_obj_get_type(str_in), &vstr); +} +#endif + // Takes an int arg, but only parses unsigned numbers, and only changes // *num if at least one digit was parsed. STATIC const char *str_to_int(const char *str, const char *top, int *num) { @@ -1806,7 +1839,7 @@ mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_u GET_STR_DATA_LEN(self_in, str_data, str_len); bufinfo->buf = (void*)str_data; bufinfo->len = str_len; - bufinfo->typecode = 'b'; + bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access return 0; } else { // can't write to a string @@ -1830,6 +1863,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split); #if MICROPY_PY_BUILTINS_STR_SPLITLINES MP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines); #endif +#if MICROPY_PY_BUILTINS_STR_CENTER +MP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center); +#endif MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); @@ -1881,6 +1917,9 @@ STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, +#if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, +#endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, diff --git a/py/objstr.h b/py/objstr.h index 6b8ad97ec2..07929156cb 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -92,6 +92,7 @@ MP_DECLARE_CONST_FUN_OBJ(str_replace_obj); MP_DECLARE_CONST_FUN_OBJ(str_count_obj); MP_DECLARE_CONST_FUN_OBJ(str_partition_obj); MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ(str_center_obj); MP_DECLARE_CONST_FUN_OBJ(str_lower_obj); MP_DECLARE_CONST_FUN_OBJ(str_upper_obj); MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj); diff --git a/py/objstringio.c b/py/objstringio.c index f50abfbc3a..5fd2ca9d3b 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -95,6 +95,7 @@ STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); check_stringio_is_open(self); + // TODO: Try to avoid copying string return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 8099e20a0e..c6c775d109 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -238,6 +238,9 @@ STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, +#if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, +#endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, diff --git a/py/parse.c b/py/parse.c index 3daa5ff83e..7da484c497 100644 --- a/py/parse.c +++ b/py/parse.c @@ -104,7 +104,7 @@ enum { #undef one_or_more #undef DEF_RULE -STATIC const rule_t *rules[] = { +STATIC const rule_t *const rules[] = { #define DEF_RULE(rule, comp, kind, ...) &rule_##rule, #include "py/grammar.h" #undef DEF_RULE @@ -449,6 +449,9 @@ STATIC void push_result_token(parser_t *parser) { #if MICROPY_COMP_MODULE_CONST STATIC const mp_rom_map_elem_t mp_constants_table[] = { + #if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, + #endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif @@ -160,6 +160,7 @@ PY_O_BASENAME = \ modmicropython.o \ modstruct.o \ modsys.o \ + moduerrno.o \ vm.o \ bc.o \ showbc.o \ @@ -173,7 +174,9 @@ PY_O_BASENAME = \ ../extmod/moduheapq.o \ ../extmod/moduhashlib.o \ ../extmod/modubinascii.o \ + ../extmod/virtpin.o \ ../extmod/machine_mem.o \ + ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ ../extmod/modussl.o \ ../extmod/modurandom.o \ @@ -88,7 +88,7 @@ bool mp_repl_continue_with_input(const char *input) { } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) { in_quote = Q_1_DOUBLE - in_quote; } - } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"')) { + } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"' || i[1] == '\\')) { if (in_quote != Q_NONE) { i++; } @@ -126,6 +126,7 @@ bool mp_repl_continue_with_input(const char *input) { mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t *print, const char **compl_str) { // scan backwards to find start of "a.b.c" chain + const char *org_str = str; const char *top = str + len; for (const char *s = top; --s >= str;) { if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { @@ -219,6 +220,16 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t // nothing found if (n_found == 0) { + // If there're no better alternatives, and if it's first word + // in the line, try to complete "import". + if (s_start == org_str) { + static const char import_str[] = "import "; + if (memcmp(s_start, import_str, s_len) == 0) { + *compl_str = import_str + s_len; + return sizeof(import_str) - 1 - s_len; + } + } + return 0; } diff --git a/py/runtime.c b/py/runtime.c index 67534c4b5e..7f28abbf4f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -714,13 +714,18 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const } } } else { - // generic mapping - // TODO is calling 'items' on the mapping the correct thing to do here? - mp_obj_t dest[2]; - mp_load_method(kw_dict, MP_QSTR_items, dest); + // generic mapping: + // - call keys() to get an iterable of all keys in the mapping + // - call __getitem__ for each key to get the corresponding value + + // get the keys iterable + mp_obj_t dest[3]; + mp_load_method(kw_dict, MP_QSTR_keys, dest); mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest)); - mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + + mp_obj_t key; + while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // expand size of args array if needed if (args2_len + 1 >= args2_alloc) { uint new_alloc = args2_alloc * 2; if (new_alloc < 4) { @@ -729,15 +734,20 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); args2_alloc = new_alloc; } - mp_obj_t *items; - mp_obj_get_array_fixed_n(item, 2, &items); + // the key must be a qstr, so intern it if it's a string - mp_obj_t key = items[0]; if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { key = mp_obj_str_intern(key); } + + // get the value corresponding to the key + mp_load_method(kw_dict, MP_QSTR___getitem__, dest); + dest[2] = key; + mp_obj_t value = mp_call_method_n_kw(1, 0, dest); + + // store the key/value pair in the argument array args2[args2_len++] = key; - args2[args2_len++] = items[1]; + args2[args2_len++] = value; } } diff --git a/py/stream.c b/py/stream.c index a3df1b8fdd..ebdbe26b45 100644 --- a/py/stream.c +++ b/py/stream.c @@ -31,6 +31,7 @@ #include "py/nlr.h" #include "py/objstr.h" #include "py/stream.h" +#include "py/runtime.h" #if MICROPY_STREAMS_NON_BLOCK #include <errno.h> @@ -49,6 +50,48 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in); #define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes) +// Returns error condition in *errcode, if non-zero, return value is number of bytes written +// before error condition occured. If *errcode == 0, returns total bytes written (which will +// be equal to input size). +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { + byte *buf = buf_; + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + io_func_t io_func; + if (flags & MP_STREAM_RW_WRITE) { + io_func = (io_func_t)s->type->stream_p->write; + } else { + io_func = s->type->stream_p->read; + } + + *errcode = 0; + mp_uint_t done = 0; + while (size > 0) { + mp_uint_t out_sz = io_func(stream, buf, size, errcode); + // For read, out_sz == 0 means EOF. For write, it's unspecified + // what it means, but we don't make any progress, so returning + // is still the best option. + if (out_sz == 0) { + return done; + } + if (out_sz == MP_STREAM_ERROR) { + // If we read something before getting EAGAIN, don't leak it + if (mp_is_nonblocking_error(*errcode) && done != 0) { + *errcode = 0; + } + return done; + } + if (flags & MP_STREAM_RW_ONCE) { + return out_sz; + } + + buf += out_sz; + size -= out_sz; + done += out_sz; + } + return done; +} + const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); const mp_stream_p_t *stream_p = o->type->stream_p; @@ -62,7 +105,14 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { return stream_p; } -STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { +mp_obj_t mp_stream_close(mp_obj_t stream) { + // TODO: Still consider using ioctl for close + mp_obj_t dest[2]; + mp_load_method(stream, MP_QSTR_close, dest); + return mp_call_method_n_kw(0, 0, dest); +} + +STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); // What to do if sz < -1? Python docs don't specify this case. @@ -94,8 +144,8 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); } int error; - mp_uint_t out_sz = stream_p->read(args[0], p, more_bytes, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error); + if (error != 0) { vstr_cut_tail_bytes(&vstr, more_bytes); if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. @@ -165,8 +215,8 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { vstr_t vstr; vstr_init_len(&vstr, sz); int error; - mp_uint_t out_sz = stream_p->read(args[0], vstr.buf, sz, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags); + if (error != 0) { vstr_clear(&vstr); if (mp_is_nonblocking_error(error)) { // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read @@ -182,20 +232,27 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } } + +STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ); +} MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read); -mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); +STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); + +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { + mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); int error; - mp_uint_t out_sz = stream_p->write(self_in, buf, len, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); + if (error != 0) { if (mp_is_nonblocking_error(error)) { // http://docs.python.org/3/library/io.html#io.RawIOBase.write // "None is returned if the raw stream is set not to block and // no single byte could be readily written to it." - // This is for consistency with read() behavior, still weird, - // see abobe. return mp_const_none; } nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); @@ -206,33 +263,25 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len) { // XXX hack void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { - mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len); -} - -// Works only with blocking streams -mp_uint_t mp_stream_writeall(mp_obj_t stream, const byte *buf, mp_uint_t size, int *errcode) { - mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); - mp_uint_t org_size = size; - while (size > 0) { - mp_uint_t out_sz = s->type->stream_p->write(stream, buf, size, errcode); - if (out_sz == MP_STREAM_ERROR) { - return MP_STREAM_ERROR; - } - buf += out_sz; - size -= out_sz; - } - return org_size; + mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } STATIC mp_obj_t stream_write_method(mp_obj_t self_in, mp_obj_t arg) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - return mp_stream_write(self_in, bufinfo.buf, bufinfo.len); + return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE); } MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write_method); +STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); + STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); @@ -248,8 +297,8 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { } int error; - mp_uint_t out_sz = stream_p->read(args[0], bufinfo.buf, len, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); + if (error != 0) { if (mp_is_nonblocking_error(error)) { return mp_const_none; } diff --git a/py/stream.h b/py/stream.h index df6e94adfd..b0f45e2f02 100644 --- a/py/stream.h +++ b/py/stream.h @@ -48,11 +48,13 @@ struct mp_stream_seek_t { }; MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); @@ -63,14 +65,20 @@ MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); #define MP_STREAM_OP_IOCTL (4) const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); +mp_obj_t mp_stream_close(mp_obj_t stream); // Iterator which uses mp_stream_unbuffered_readline_obj mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); -mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len); +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags); -// Helper function to write entire buf to *blocking* stream -mp_uint_t mp_stream_writeall(mp_obj_t stream, const byte *buf, mp_uint_t size, int *errcode); +// C-level helper functions +#define MP_STREAM_RW_READ 0 +#define MP_STREAM_RW_WRITE 2 +#define MP_STREAM_RW_ONCE 1 +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, byte flags); +#define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte*)buf, size, err, MP_STREAM_RW_WRITE) +#define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ) #if MICROPY_STREAMS_NON_BLOCK // TODO: This is POSIX-specific (but then POSIX is the only real thing, diff --git a/py/vmentrytable.h b/py/vmentrytable.h index f3143b5d1d..9df1e40a32 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -29,7 +29,7 @@ #pragma clang diagnostic ignored "-Winitializer-overrides" #endif // __clang__ -static void* entry_table[256] = { +static const void *const entry_table[256] = { [0 ... 255] = &&entry_default, [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE, [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE, @@ -151,7 +151,7 @@ STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { if (vstr->fixed_buf) { return false; } - size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 64); + size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16); char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); if (new_buf == NULL) { vstr->had_error = true; @@ -181,9 +181,15 @@ char *vstr_add_len(vstr_t *vstr, size_t len) { // Doesn't increase len, just makes sure there is a null byte at the end char *vstr_null_terminated_str(vstr_t *vstr) { - if (vstr->had_error || !vstr_ensure_extra(vstr, 1)) { + if (vstr->had_error) { return NULL; } + // If there's no more room, add single byte + if (vstr->alloc == vstr->len) { + if (vstr_extend(vstr, 1) == NULL) { + return NULL; + } + } vstr->buf[vstr->len] = '\0'; return vstr->buf; } |