summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-08-13 21:33:40 +1000
committerDamien George <damien.p.george@gmail.com>2017-08-13 21:33:40 +1000
commite52758da223e57b6cd9458f039f8ccc50ee76ddb (patch)
tree2d5218ad0e1f30c686f51f5807b5676fe0007fe5 /py
parentbe2387885bf251fb44b6b64aeadff147a4ae7266 (diff)
parent9b39263b118a4be65c58bf9c396203fa535bebe1 (diff)
downloadmicropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.tar.gz
micropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.zip
Merge tag 'v1.8.1' into parse-bytecode
Many ESP8266 improvements, enhanced WebREPL, and support for STM32L4 MCUs This release brings general improvements and bug fixes, and some new features. There is now a uerror module for consistent errno handling across ports, as well as textual names of OS errors that are printed when an OSError is raised. There is support for frozen packages, via both frozen scripts and frozen bytecode. WebREPL on the ESP8266 is greatly improved with many bug fixes and now supports an unlimited (or very large) number of reconnects. The os module on the ESP8266 now has rename, chdir, getcwd and stat. The unix port now includes the ussl module by default. The stmhal port has support for STM32L4 MCUs including the STM32L476 Discovery board and the LimiFrog board. README: - add explicit note that subdirs contain more READMEs - add "make deplibs" to quick build section - "quick build": Use "make axtls" after all CODECONVENTIONS.md: - describe git commit messages conventions py core: - obj: add warning note about get_array return value and GC blocks - objstr: binary type of str/bytes for buffer protocol is 'B' - runtime: properly handle passing user mappings to ** keyword args - repl: if there're no better alternatives, try to complete "import" - mpz: fix bug with overflowing C-shift in division routine - mpz: do Python style division/modulo within bignum divmod routine - mpz: fix mpn_div so that it doesn't modify memory of denominator - vstr: vstr_null_terminated_str(): Extend string by at most one byte - vstr: change allocation policy, +16 to requested size, instead of *2 - add mperrno.h file with uPy defined errno constants - add uerrno module, with errno constants and dict - parse: add uerrno to list of modules to look for constants in - mperrno: add EAFNOSUPPORT definition - repl: fix handling of backslash in quotes when checking continuation - gc: gc_dump_alloc_table(): Show byte/str and (byte)array objects - gc: make (byte)array type dumping conditional on these types being enabled - gc: use '=' char for tail blocks when dumping heap - mperrno: add some more MP_Exxx constants, related to networking - moduerrno: add more constants to the errno module - add mp_errno_to_str() and use it to provide nicer OSError msgs - objfloat, py/modmath: ensure M_PI and M_E defined - emitglue: fix build on AArch64 (ARMv8, etc.) related to loading .mpy files - objexcept: don't convert errno to str in constructor, do it in print - moduerrno: add EACCES, pretty common error on Unix - gc: gc_dump_alloc_table(): dump heap offset instead of actual address - objstr: make dedicated splitlines function, supporting diff newlines - objstringio: add TODO comment about avoiding copying on .getvalue() - modstruct: raise ValueError on unsupported format char - stream: support both "exact size" and "one underlying call" operations - declare constant data as properly constant - stream: add mp_stream_close() helper function - mphal.h: provide default prototypes for mp_hal_delay_us/mp_hal_ticks_us - rework frozen modules support to support packages - objstr: implement str.center() - allow to stat and import frozen mpy files using new frozen "VFS" - makeqstrdata.py: allow to have double-quote characters in qstrs - objnamedtuple: allow passing field names as a tuple - moduerrno: add EEXIST, EISDIR, ECONNREFUSED - modstruct: allow to have "0s" in struct format extmod: - modlwip: convert errno's to use MP_Exxx symbols - modlwip: rework how Python accept callback is called - when including extmod headers, prefix path with extmod/ - modwebsocket: add close() method - modwebrepl: add close() method - moduos_dupterm: dumpterm subsystem is responsible for closing stream - modussl: make more compatible with non-default obj representations - machine_i2c: redo mp_hal_pin macros to use open_drain and od_low - virtpin: initial implementation of open-ended C-level Pin interface - vfs_fat: replace text error messages by POSIX error numbers - vfs_fat: add chdir() method - vfs_fat: add getcwd() method - vfs_fat: add vfs.stat() method - add machine time_pulse_us function (at C and Python level) - machine: add MICROPY_PY_MACHINE_PULSE config for time_pulse_us lib: - timeutils/timeutils: timeutils_mktime may accept negative time values drivers: - cc3000: rename timeval to cc3000_timeval, to avoid clash - add C-level function to read DHT11 and DHT22 devices - display/ssd1306: update SSD1306_SPI to work with new API tools: - make-frozen.py: properly escape hex chars when making C strings - make-frozen.py: quick fix to support package-modules - mpy-tool.py: add checks for critical configuration vars - make-frozen.py: update for latest changes in frozen modules support - mpy-tool.py: include .py extension in frozen filename - mpy-tool.py: don't strip directories from the frozen source name - upgrade upip to 0.7: SSL cert warning, use uerrno, better usage message tests: - run-tests: factor out list of supported external boards - disable memoryview tests that overflow int conversion - basics/string_splitlines: reinstate feature test for splitlines - struct1: add testcase for an unknown type char - add testcase for str.center() - extmod/vfs_fat_ramdisk: add testcases for chdir(), getcwd() - misc/recursive_iternext.py: increase depth N from 1000 to 2000 - misc/recursive_iternext.py: provide more fine-grained selection of N - pyb/rtc: make RTC test on pyboard more reliable by calling init() mpy-cross: - add -s option to specify the embedded source filename unix port: - mphalport: add mp_hal_delay_us() for consistency with other ports - enable uerrno module - add ability to include frozen bytecode in the build - mpconfigport_coverage.h: add dedicated config file for coverage build - unix_mphal: implement mp_hal_ticks_us() - support frozen packages - Makefile: nanbox build is not compatible with modussl, disable - enable "ussl" module - mpconfigport.mk: document MICROPY_STANDALONE make-level option - Makefile: "make axtls": automatically fetch submodules if missing windows port: - enable multi-processor compilation for msvc stmhal port: - l4: adapt DMA to be able to support STM32L4 MCU series - l4: adapt startup code, clock configuration and interrupts - l4: make CCM/DTCM RAM start-up conditional on MCU type - l4: add support for machine.sleep on STM32L4 MCUs - dma: make DAC DMA descriptors conditional on having a DAC - add board files for LIMIFROG board - for LIMIFROG board, add early-init function to get to DFU mode - dma: fix builds for boards with an F4 or F7 but no DAC - sdcard: fix initialisation of DMA TX so that writes work - can: allow to get existing CAN obj if constructed without args - fix clock configuration for STM32L476-discovery; also add I2C2 - convert to use internal errno symbols; enable uerrno module - for network drivers, convert to use MP_Exxx errno symbols - led: allow LEDs to be in PWM mode with TIM1 and channels 1-4 - i2c: expose I2CHandle3 for use by custom C code - sdcard: allow to do unaligned read-from/write-to SD card - support frozen packages using .mpy files - moduos: getcwd(): use mp_obj_new_exception_arg1() - dac: add DAC deinit() method - uart: fix wrong baudrate calculation for stm32l4 series esp8266 port: - scripts/: remove use of pin.PULL_NONE - scripts/inisetup: don't start WebREPL on boot in master branch - scripts/: add fill() to NeoPixel - scripts/webrepl: add optional password argument to webrepl.start() - scripts/webrepl: add start_foreground() method - main: bump heap size to 28K - mpconfigport: reduce various parser-related allocation params - help: add "sta_if.active(True)" command - convert to use new MP_Exxx errno symbols - enable uerrno module, weak linked also as errno - change to use internal errno's - moduos.c: addition of the rename method to module uos - scripts/port_diag: add network diagnostic output - scripts/webrepl_setup: show password placeholder char - scripts/webrepl_setup: add max password length check - README: add a very first start section - add APA102 serial individually controllable LEDs support - enable collections.OrderedDict - main: update _boot module loading for recent frozen modules refactors - scripts/port_diag: dump network interface IP settings - esp_mphal: fix NLR buffer leak in call_dupterm_read() - esp_mphal: handle Ctrl+C from dupterm (e.g. WebREPL) - esp_mphal: mp_uos_dupterm_deactivate() may raise exception - add mp_hal_pin_input() and mp_hal_pin_output() functions - modpybspi: configure pins when initialising an SPI object - xtirq: add xtirq.h for controlling xtensa irqs - ets_alt_task: don't run ets_loop_iter if irqs are disabled - modmachine: add disable_irq and enable_irq functions - enable DHT C-level driver - add dht.py script for high-level control of DHT11/DHT22 sensor - Makefile: document "disable" value for UART_OS - modnetwork: scan() is only supported by STA when it's enabled - modnetwork: protect scan() callback against memory errors - modnetwork: allow to press ctrl-C while scan() is running - uart: properly initialise UART0 RXD pin in uart_config - moduos: add chdir() and getcwd() functions - scripts/ntptime: allow to override NTP server - modmachine: add machine.time_pulse_us function - enable MICROPY_PY_IO_FILEIO to get compliant text/binary streams - moduos.c: add stat() to the module uos of esp8266 - rtc: set RTC user memory length to 0 on first boot - provide a dedicated variable to disable ets_loop_iter - modpybrtc: handle RTC overflow docs: - machine.UART: filter out unimplemented UART methods from esp8266 docs - esp8266/quickref: new way to get MAC address - esp8266/quickstart: remove i2c examples with stop=False - ustruct: describe supported type codes - ussl: add basic description of axTLS-based modussl - esp8266: Include ussl module in the docs - machine: make disable_irq and enable_irq docs available for all - library/machine: add documentation for machine.time_pulse_us - math, cmath: add port availability information - library/index: add intro paragraph regarding availability of modules - README: add some hints for PDF docs generation - wipy/tutorial: add note about screen key bindings on OS X - esp8266/quickref: update WebREPL section for 1.8.1 release - esp8266: fix ESP8266 Network tutorial - esp8266/quickref: use local image of Adafruit Huzzah board - esp8266/general: add note about RTC overflow travis: - install gcc-arm-none-eabi with --force-yes for now
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;
}