summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/builtin.h1
-rw-r--r--py/builtinimport.c83
-rw-r--r--py/compile.c2
-rw-r--r--py/emitglue.c2
-rw-r--r--py/frozenmod.c37
-rw-r--r--py/frozenmod.h1
-rw-r--r--py/gc.c14
-rw-r--r--py/lexer.c4
-rw-r--r--py/makeqstrdata.py2
-rw-r--r--py/map.c2
-rw-r--r--py/modio.c14
-rw-r--r--py/modmath.c5
-rw-r--r--py/modstruct.c25
-rw-r--r--py/moduerrno.c105
-rw-r--r--py/mpconfig.h20
-rw-r--r--py/mperrno.h143
-rw-r--r--py/mphal.h17
-rw-r--r--py/mpz.c67
-rw-r--r--py/obj.c2
-rw-r--r--py/obj.h4
-rw-r--r--py/objdict.c2
-rw-r--r--py/objexcept.c11
-rw-r--r--py/objfloat.c8
-rw-r--r--py/objint_mpz.c14
-rw-r--r--py/objmodule.c3
-rw-r--r--py/objnamedtuple.c5
-rw-r--r--py/objstr.c83
-rw-r--r--py/objstr.h1
-rw-r--r--py/objstringio.c1
-rw-r--r--py/objstrunicode.c3
-rw-r--r--py/parse.c5
-rw-r--r--py/py.mk3
-rw-r--r--py/repl.c13
-rw-r--r--py/runtime.c30
-rw-r--r--py/stream.c111
-rw-r--r--py/stream.h14
-rw-r--r--py/vmentrytable.h2
-rw-r--r--py/vstr.c10
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);
diff --git a/py/gc.c b/py/gc.c
index 41526c8b09..ca332860f5 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -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
diff --git a/py/map.c b/py/map.c
index 445b206603..0916ec522d 100644
--- a/py/map.c
+++ b/py/map.c
@@ -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__
diff --git a/py/mpz.c b/py/mpz.c
index 2c02699811..bb76479569 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -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);
+ }
}
}
diff --git a/py/obj.c b/py/obj.c
index 91dd4c0905..9efa0f05ae 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -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);
diff --git a/py/obj.h b/py/obj.h
index 6b0f441752..83f0406ce4 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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
diff --git a/py/py.mk b/py/py.mk
index db173156ed..e3057eb4ec 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -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 \
diff --git a/py/repl.c b/py/repl.c
index 7bd8759084..997d800054 100644
--- a/py/repl.c
+++ b/py/repl.c
@@ -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,
diff --git a/py/vstr.c b/py/vstr.c
index 181b1c49b9..2e53744362 100644
--- a/py/vstr.c
+++ b/py/vstr.c
@@ -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;
}