diff options
author | Damien George <damien.p.george@gmail.com> | 2017-08-14 12:47:47 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-08-14 12:47:47 +1000 |
commit | f6e6776d6f8233432615f1ef438cbd1447c51aac (patch) | |
tree | 34589f98ab4d89914025b7d4ee10d2801cd80b3d /py | |
parent | d9d9b0a3005a810543724622374cc26a5399bd0e (diff) | |
parent | c8d31585a00616b39839d112b7c696dafed6b08d (diff) | |
download | micropython-f6e6776d6f8233432615f1ef438cbd1447c51aac.tar.gz micropython-f6e6776d6f8233432615f1ef438cbd1447c51aac.zip |
Merge tag 'v1.8.5' into parse-bytecode
New port to Zephyr, upip runs on baremetal, and reduction in code size
This release adds a new port of MicroPython to run on top of the Zephyr
real-time operating system. As part of this there is now basic support for
using mbedTLS as the ussl module. The release also brings initial support
for running the package manager upip on baremetal systems with low heap
memory (such as esp8266), through a Python module interface.
Work has been done in this release to clean up the core, removing redundant
and/or unreachable code, and factoring existing duplicated code patterns.
This brings a reduction of 828 bytes in code size to the bare-arm port, and
1368 bytes to the minimal port. There is also improved coverage through
the addition of new tests for corner cases.
The "micropython" module sees the addition of the "const" identity function
which should be used as "from micropython import const" in scripts that
want to use the MicroPython constant optimisations in the compile stage.
There is also the addition of the "opt_level" function to change the
parser/compiler optimisation level at runtime.
The behaviour of "sys.exit" (and "raise SystemExit") on baremetal is now
changed: this function no longer does a soft-reset of the board, rather it
just stops the running script and drops to the REPL. In order to do an
actual soft reset the "machine.soft_reset" function has been added (to the
stmhal port only, for the time being).
Following CPython, KeyError exceptions for dictionary lookups now have the
failed key stored as the argument of the exception instance, accessible as
exc.args[0]. The "ujson.load" function has also been added, to load JSON
data from an arbitrary stream.
The I2C support in the machine module now has clock stretching, the
addition of the "addrsize" parameter in memory transfer methods, and I2C
scanning now uses dummy writes instead of dummy reads to make the scanning
more reliable.
The CMSIS library has been upgrade to v4.30, and the boards section of
the stmhal port has been refactored to use a common.ld script. The stmhal
port now has a full implementation of the machine.SPI class, with support
for both hardware SPI peripherals and fast software SPI. The USB HID
driver in stmhal has added support to receive USB HID messages from the
host.
py core:
- asmthumb: flush D-cache, and invalidate I-cache on STM32F7
- makeqstrdefs.py: use python 2.6 syntax for set creation
- objnone: remove unnecessary handling of MP_UNARY_OP_BOOL
- move frozen modules rules from esp8266 port for reuse across ports
- combine 3 comprehension emit functions (list/dict/set) into 1
- combine 3 comprehension opcodes (list/dict/set) into 1
- vstr: remove vstr.had_error flag and inline basic vstr functions
- objnone: use mp_generic_unary_op instead of custom one
- showbc: make printf's go to the platform print stream
- remove 'name' member from mp_obj_module_t struct
- builtinimport: fix nanbox build after change to better handle -m modules
- stream: remove unnecessary check for NULL return from vstr_extend
- py.mk: suppress some compiler warnings when building berkeley-db
- shrink mp_arg_t struct by using reduced-size integer members
- update opcode format table because 3 opcodes were removed, 1 added
- parse: only replace constants that are standalone identifiers
- py.mk: add support for building modussl_mbedtls
- only store the exception instance on Py stack in bytecode try block
- vm: use MP_OBJ_FROM_PTR to cast a type to an object
- modmicropython: add micropython.const, alias for identity function
- objstr: remove unreachable function used only for terse error msgs
- emitbc: remove/refactor unreachable code, to improve coverage
- objfun: remove unnecessary check for viper fun with 5 or more args
- objfun: use if instead of switch to check return value of VM execute
- objset: use mp_check_self() to check args of set/frozenset methods
- objset: ensure that use of frozenset.update raises an exception
- compile: fix async-for/async-with to work with simpler exc on stack
- scope: use lookup-table to determine a scope's simple name
- scope: shrink scope_t struct by 1 machine word
- scope: factor common code to find locals and close over them
- compile: fix typo when checking for parse-node kind
- argcheck: simplify if-chain so that the last one is the default
- objbool: defer bool's unary op implementation to small int
- objbool: make a slight simplification of bool constructor
- modstruct: remove unreachable code, and add comment about CPy diff
- add mp_raise_OSError(errno) helper function
- objstringio: add readinto() method
- modmicropython: add micropython.opt_level([value]) function
- compile: remove unreachable code
- mpz: in divmod, replace check for rhs!=0 with assert
- mpz: use assert to verify mpz does not have a fixed digit buffer
- factor duplicated function to calculate size of formatted int
- objint: use size_t for arguments that measure bytes/sizes
- compile: remove debugging code for compiler dispatch
- lexer: remove unnecessary code, and unreachable code
- vstr: combine vstr_new_size with vstr_new since they are rarely used
- objdict: fix optimisation for allocating result in fromkeys
- objdict: actually provide the key that failed in KeyError exception
- use mp_raise_msg helper function where appropriate
- add the module specified by -m to sys.modules as '__main__'
extmod:
- modussl_mbedtls: initial implementation of mbedTLS ussl module
- uctypes: allow full 32-bit address range
- modubinascii: fix crc32() function on 32-bit platforms
- modussl_mbedtls: implement key= and cert= args to wrap_socket()
- modussl_mbedtls: use 2-component include paths
- machine_i2c: add clock stretching support
- modussl_mbedtls: add server_hostname param for wrap_socket()
- uzlib: add tinfgzip.c (gzip header parsing) from upstream
- moduzlib: DecompIO: Add support for gzip-formatted streams
- uzlib/: update uzlib to v2.0.3
- vfs_fat: add fat_vfs_statvfs(), reused from stmhal
- machine_i2c: add support for the addrsize parameter in mem xfers
- machine_spi: simplify SPI xfer function to only take one buf len
- machine_spi: factor out software SPI code from esp8266 to extmod
- machine_spi: use delay_half, not baudrate, for internal timing
- machine_spi: add optional support for fast software SPI
- vfs_fat: use mp_raise_OSError helper function
- modlwip: use mp_raise_OSError helper function
- use mp_raise_OSError helper function
- vfs_fat_file: use MP_Exxx errno constants
- uzlib: update to upstream v2.1
- machine_i2c: use writes not reads in i2c.scan()
- vfs_fat: add file and directory checks for remove and rmdir
- modujson: implement ujson.load() to load JSON from a stream
- modujson: fix nanbox build
- utime_mphal: factor out implementations in terms of mp_hal_* for reuse
- utime_mphal: sleep_us/ms(): Don't wait on negative argument
- modussl_mbedtls: add dummy setblocking() method
lib:
- interrupt_char: factor out typical Ctrl+C handling from esp8266 port
- cmsis: move CMSIS headers to lib/
- cmsis: remove CMSIS-DSP headers, they are unused
- cmsis: upgrade CMSIS-CORE to V4.30
- utils/pyexec: don't treat SystemExit as "forced exit"
- utils/pyexec: allow behaviour of SystemExit to be configurable
drivers:
- dht: use mp_raise_OSError helper function
tools:
- update upip to 0.8, fixes IPv6 support
- upgrade upip to 1.0, fully self-hosted release (without fallbacks), and
uses stream gzip decompression (step towards support for limited-heap
baremetal systems)
- upgrade upip to 1.1.3, initial support for running on a baremetal,
low-heap systems (like esp8266), using Python module interface
tests:
- pyb: add test for ExtInt when doing swint while disabled
- pyb: update exp file for previously updated extint test
- extmod/urandom: add urandom tests for error cases
- basics: add errno1 test, to check basics of uerrno module
- extmod: add test for machine.time_pulse_us()
- struct1: test "l" specifier to improve coverage
- array1: add tests for "l", "L" array types to improve coverage
- get cmdline verbose tests running again
- run-tests: add --via-mpy option to run test from precompiled code
- uzlib_decompio_gz: test for DecompIO with gzip bitstream
- basics: add test case for overflowing Py stack in try-finally
- micropython: add tests for const names being replaced in parser
- cmdline/cmd_showbc: fix test now that 1 value is stored on stack
- extmod/vfs_fat_ramdisk: add test for VFS.statvfs()
- float: add test for parsing a float from an empty string
- basics: add test for set.difference_update with arg being itself
- basics: add further tests for nonlocal scoping and closures
- import: add test for compiling "import a.b as c"
- basics: add test constructing a set from a non-trivial expression
- basics: add test for printing OSError when errno is unknown
- run-tests: disable cmdline/cmd_showbc test on Windows
- extmod/btree1: checks for put, seq, string print and unsupported binary op
- fix expected output of verbose cmdline test
- extmod/uzlib: test adaptive huffman tree for tinflate coverage
- improve coverage of struct with test for non-compliant behaviour
- io/write_ext: add description comment
- io/bytesio_ext: add test for readinto()
- micropython: add test for micropython.opt_level() function
- improve test coverage of py/compile.c
- extmod/vfs_fat: test coverage for remove() and rmdir()
- extmod: add test for ujson.load()
- extmod/vfs_fat: replace asserts with prints and expected outputs
- micropython: add tests for heap_lock, and emergency exceptions
- cmdline: improve coverage test for printing bytecode
- improve coverage of array, range, dict, slice, exc, unicode
- add test to print full KeyError exc from failed dict lookup
- run-tests: enable extmod/machine1.py on pyboard
unix port:
- fix build for when MICROPY_PY_SOCKET=0
- modjni: implement subscription for object arrays
- modjni: add array() top-level function to create Java array
- modjni: array(): Support creation of object arrays
- enable btree module for coverage build
- use mp_raise_OSError helper function
- use common RAISE_ERRNO macro from mphalport.h
windows port:
- enable MICROPY_PY_UERRNO
qemu-arm port:
- enable lots of extmods and enable tests for them
stmhal port:
- lcd: de-assert chip select after completing SPI transmission
- {accel,lcd}: use GPIO_{set,clear}_pin
- extint: force 0 to 1 transition on swint()
- boards: add pllvalues.py script to compute PLL values for sysclk
- boards: for OLIMEX_E407, enable UART1 and fix I2C1 mapping
- use attribute to avoid inlining
- put common definitions from linker files to common.ld
- remove STM32CubeF2 HAL files, they are unused/unsupported
- modmachine: fix clearing of reset-cause flags
- add virtual com port support for STM32L476DISC
- remove CMSIS STM32F2xx files, they are unused/unsupported
- spi: simplify spi_transfer function to take only one buf len arg
- mphalport: implement mp_hal_pin_{input,output,write}
- spi: make machine.SPI class conform to correct API
- mphalport: fix mp_hal_pin_write to use correct pin_mask
- spi: use software SPI if no periph id given, even if pins given
- spi: enable use of fast software SPI
- fix linker map for STM32L476 chips
- usbdev: add OUT endpoint to HID interface
- usb: add support to receive USB HID messages from host
- usb: use correct ClassData structure for HID receive
- usb: use real packet size (not maximum) in HID receive
- fix ESPRUINO_PICO by adding ld scripts with correct flash size
- mphalport: change pin obj type to const pointer, to avoid casts
- moduos: implement total-number-of-blocks field in statvfs
- disable network and usocket for ESPRUINO_PICO
- enable machine.time_pulse_us() function
- use mp_raise_OSError helper function
- pybstdio: use size_t instead of mp_uint_t
- modutime: refactor to use extmod/utime_mphal.c
- implement machine.soft_reset()
- enable str.center(), str.[r]partition() and builtin compile()
cc3200 port:
- add ssl_version argument to ssl.wrap_socket()
esp8266 port:
- Makefile: rename SCRIPTDIR to FROZEN_DIR for consistency with FROZEN_MPY_DIR
- ets_alt_task: ets_post: Should return 0 on success, !0 - failure
- esp_mphal: add tentative change to mp_hal_stdin_rx_chr() to wait IRQ
- extend system microsecond counter to 64-bits; use in ticks_ms
- add uos.statvfs() to get filesystem status
- moduos: move stat/statvfs funcs to sit within #if VFS guard
- modmachine: idle(): Return number of CPU cycles spent idling
- main: put /lib before / in sys.path
- modpybrtc.c: implement machine.RTC.alarm_left()
- make PY_UHASHLIB_SHA1 config depend on PY_USSL and SSL_AXTLS
- add FLASH_MODE,FLASH_SIZE options for make deploy target
- use mp_raise_OSError helper function
- make neopixel support configurable
- mpconfigport: enable MICROPY_PY_BUILTINS_SLICE_ATTRS
- enable sys.{stdin,stdout,stderr}.buffer for raw serial access
- enable importing of precompiled .mpy files
- enable micropython.alloc_emergency_exception_buf()
zephyr port:
- initial Zephyr RTOS port, MicroPython part
- initial Zephyr RTOS port, Zephyr part
- add zephyr_getchar module to handle console input
- switch to microkernel, required for network to work in background
- automatically derive ARCH
- support extra make targets
- Makefile: automatically derive target-specific CFLAGS
- use recently added "make outputexports" Zephyr target
- add README
- enable stack checking and micropython.mem_info()
- enable frozen modules support
- main: execute main.py frozen module on boot, if available
- zephyr_getchar: add support for Ctrl+C handling
- add Ctrl+C handling
- implement the help() function
- add copyright blurbs
README:
- remove issue-stats badges, the service is no longer available
- mention _thread module availability in select ports
docs:
- library/pyb.SPI: init(): describe "bits" argument
- library/machine: update description of disable/enable IRQ funcs
- uos: add uos.statvfs() documentation
- wipy: correct deep sleep current figure
- wipy: small doc fixes
- reference: add constrained.rst doc
travis:
- abandon mingw32 in favour of mingw-w64
- run feature and coverage test for precompiled mpy files
examples:
- network/http_client*: use \r\n line-endings in request
Diffstat (limited to 'py')
-rw-r--r-- | py/argcheck.c | 16 | ||||
-rw-r--r-- | py/asmthumb.c | 9 | ||||
-rw-r--r-- | py/bc.c | 9 | ||||
-rw-r--r-- | py/bc0.h | 4 | ||||
-rw-r--r-- | py/builtinevex.c | 2 | ||||
-rw-r--r-- | py/builtinimport.c | 10 | ||||
-rw-r--r-- | py/compile.c | 83 | ||||
-rw-r--r-- | py/emit.h | 8 | ||||
-rw-r--r-- | py/emitbc.c | 73 | ||||
-rw-r--r-- | py/emitcommon.c | 16 | ||||
-rw-r--r-- | py/emitglue.c | 2 | ||||
-rw-r--r-- | py/emitnative.c | 67 | ||||
-rw-r--r-- | py/lexer.c | 15 | ||||
-rw-r--r-- | py/makeqstrdefs.py | 2 | ||||
-rw-r--r-- | py/misc.h | 11 | ||||
-rw-r--r-- | py/mkenv.mk | 2 | ||||
-rw-r--r-- | py/mkrules.mk | 6 | ||||
-rw-r--r-- | py/modarray.c | 1 | ||||
-rw-r--r-- | py/modbuiltins.c | 12 | ||||
-rw-r--r-- | py/modcmath.c | 1 | ||||
-rw-r--r-- | py/modcollections.c | 1 | ||||
-rw-r--r-- | py/modgc.c | 1 | ||||
-rw-r--r-- | py/modio.c | 3 | ||||
-rw-r--r-- | py/modmath.c | 1 | ||||
-rw-r--r-- | py/modmicropython.c | 13 | ||||
-rw-r--r-- | py/modstruct.c | 5 | ||||
-rw-r--r-- | py/modsys.c | 1 | ||||
-rw-r--r-- | py/modthread.c | 5 | ||||
-rw-r--r-- | py/moduerrno.c | 1 | ||||
-rw-r--r-- | py/mpconfig.h | 6 | ||||
-rw-r--r-- | py/mphal.h | 4 | ||||
-rw-r--r-- | py/mpprint.c | 4 | ||||
-rw-r--r-- | py/mpz.c | 41 | ||||
-rw-r--r-- | py/mpz.h | 1 | ||||
-rw-r--r-- | py/obj.c | 31 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objarray.c | 4 | ||||
-rw-r--r-- | py/objbool.c | 23 | ||||
-rw-r--r-- | py/objcomplex.c | 4 | ||||
-rw-r--r-- | py/objdict.c | 17 | ||||
-rw-r--r-- | py/objfloat.c | 2 | ||||
-rw-r--r-- | py/objfun.c | 33 | ||||
-rw-r--r-- | py/objgenerator.c | 6 | ||||
-rw-r--r-- | py/objint.c | 26 | ||||
-rw-r--r-- | py/objint.h | 8 | ||||
-rw-r--r-- | py/objint_longlong.c | 2 | ||||
-rw-r--r-- | py/objint_mpz.c | 13 | ||||
-rw-r--r-- | py/objlist.c | 2 | ||||
-rw-r--r-- | py/objmodule.c | 13 | ||||
-rw-r--r-- | py/objnamedtuple.c | 2 | ||||
-rw-r--r-- | py/objnone.c | 11 | ||||
-rw-r--r-- | py/objobject.c | 3 | ||||
-rw-r--r-- | py/objset.c | 31 | ||||
-rw-r--r-- | py/objstr.c | 5 | ||||
-rw-r--r-- | py/objstringio.c | 14 | ||||
-rw-r--r-- | py/objstringio.h | 38 | ||||
-rw-r--r-- | py/objtype.c | 21 | ||||
-rw-r--r-- | py/parse.c | 23 | ||||
-rw-r--r-- | py/parsenum.c | 4 | ||||
-rw-r--r-- | py/py.mk | 9 | ||||
-rw-r--r-- | py/qstr.c | 1 | ||||
-rw-r--r-- | py/runtime.c | 58 | ||||
-rw-r--r-- | py/runtime.h | 5 | ||||
-rw-r--r-- | py/scope.c | 89 | ||||
-rw-r--r-- | py/scope.h | 21 | ||||
-rw-r--r-- | py/sequence.c | 2 | ||||
-rw-r--r-- | py/showbc.c | 24 | ||||
-rw-r--r-- | py/stream.c | 24 | ||||
-rw-r--r-- | py/vm.c | 97 | ||||
-rw-r--r-- | py/vmentrytable.h | 4 | ||||
-rw-r--r-- | py/vstr.c | 69 |
71 files changed, 515 insertions, 661 deletions
diff --git a/py/argcheck.c b/py/argcheck.c index 5733c77f1d..8cef10b165 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -37,8 +37,7 @@ void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "function does not take keyword arguments")); + mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); } } @@ -105,10 +104,9 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n out_vals[i].u_bool = mp_obj_is_true(given_arg); } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) { out_vals[i].u_int = mp_obj_get_int(given_arg); - } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ) { - out_vals[i].u_obj = given_arg; } else { - assert(0); + assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ); + out_vals[i].u_obj = given_arg; } } if (pos_found < n_pos) { @@ -117,8 +115,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "extra positional arguments given")); + mp_raise_msg(&mp_type_TypeError, "extra positional arguments given"); } } if (kws_found < kws->used) { @@ -126,8 +123,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "extra keyword arguments given")); + mp_raise_msg(&mp_type_TypeError, "extra keyword arguments given"); } } } @@ -140,7 +136,7 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER NORETURN void mp_arg_error_terse_mismatch(void) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch")); + mp_raise_msg(&mp_type_TypeError, "argument num/types mismatch"); } #endif diff --git a/py/asmthumb.c b/py/asmthumb.c index 8341c958e9..1aae3d38eb 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -90,6 +90,15 @@ void asm_thumb_start_pass(asm_thumb_t *as, uint pass) { void asm_thumb_end_pass(asm_thumb_t *as) { (void)as; // could check labels are resolved... + + #if defined(MCU_SERIES_F7) + if (as->pass == ASM_THUMB_PASS_EMIT) { + // flush D-cache, so the code emited is stored in memory + SCB_CleanDCache_by_Addr((uint32_t*)as->code_base, as->code_size); + // invalidate I-cache + SCB_InvalidateICache(); + } + #endif } // all functions must go through this one to emit bytes @@ -185,7 +185,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, siz } // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); + mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; @@ -234,8 +234,7 @@ continue2:; } else { // no keyword arguments given if (n_kwonly_args != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "function missing keyword-only argument")); + mp_raise_msg(&mp_type_TypeError, "function missing keyword-only argument"); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); @@ -308,8 +307,8 @@ STATIC const byte opcode_format_table[64] = { OC4(B, B, O, U), // 0x44-0x47 OC4(U, U, U, U), // 0x48-0x4b OC4(U, U, U, U), // 0x4c-0x4f - OC4(V, V, V, V), // 0x50-0x53 - OC4(B, V, V, V), // 0x54-0x57 + OC4(V, V, U, V), // 0x50-0x53 + OC4(B, U, V, V), // 0x54-0x57 OC4(V, V, V, B), // 0x58-0x5b OC4(B, B, B, U), // 0x5c-0x5f OC4(V, V, V, V), // 0x60-0x63 @@ -82,13 +82,11 @@ #define MP_BC_BUILD_TUPLE (0x50) // uint #define MP_BC_BUILD_LIST (0x51) // uint -#define MP_BC_LIST_APPEND (0x52) // uint #define MP_BC_BUILD_MAP (0x53) // uint #define MP_BC_STORE_MAP (0x54) -#define MP_BC_MAP_ADD (0x55) // uint #define MP_BC_BUILD_SET (0x56) // uint -#define MP_BC_SET_ADD (0x57) // uint #define MP_BC_BUILD_SLICE (0x58) // uint +#define MP_BC_STORE_COMP (0x57) // uint #define MP_BC_UNPACK_SEQUENCE (0x59) // uint #define MP_BC_UNPACK_EX (0x5a) // uint diff --git a/py/builtinevex.c b/py/builtinevex.c index 74c43b1768..636f869300 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -95,7 +95,7 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break; case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode")); + mp_raise_msg(&mp_type_ValueError, "bad compile mode"); } mp_obj_code_t *code = m_new_obj(mp_obj_code_t); diff --git a/py/builtinimport.c b/py/builtinimport.c index ef3545d653..e72eaf4724 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -138,7 +138,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char if (lex == NULL) { // we verified the file exists using stat, but lexer could still fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found")); + mp_raise_msg(&mp_type_ImportError, "module not found"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%s'", fname)); @@ -340,7 +340,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Warning: no dots in current module name and level>0\n"); p = this_name + this_name_l; } else if (level != -1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import")); + mp_raise_msg(&mp_type_ImportError, "invalid relative import"); } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); @@ -355,7 +355,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); if (new_mod_q == MP_QSTR_) { // CPython raises SystemError - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "cannot perform relative import")); + mp_raise_msg(&mp_type_ImportError, "cannot perform relative import"); } module_name = MP_OBJ_NEW_QSTR(new_mod_q); mod_str = new_mod; @@ -425,7 +425,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { #endif // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found")); + mp_raise_msg(&mp_type_ImportError, "module not found"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", mod_name)); @@ -448,6 +448,8 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); #if MICROPY_CPYTHON_COMPAT + // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules). + mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj); // Store real name in "__main__" attribute. Choosen semi-randonly, to reuse existing qstr's. mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name)); #endif diff --git a/py/compile.c b/py/compile.c index c8b4e5470d..f84d5e2145 100644 --- a/py/compile.c +++ b/py/compile.c @@ -499,8 +499,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ // sequence of many items uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2); c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) { - // TODO can we ever get here? can it be compiled? + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { goto cannot_assign; } else { // sequence with 2 items @@ -900,8 +899,7 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { for (int i = 0; i < n; i++) { c_del_stmt(comp, pns1->nodes[i]); } - } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) { - // TODO not implemented; can't del comprehension? can we get here? + } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) { goto cannot_delete; } else { // sequence with 2 items @@ -1172,17 +1170,14 @@ STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) { bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); - if (!added && id_info->kind != ID_INFO_KIND_FREE) { + if (added) { + scope_find_local_and_close_over(comp->scope_cur, id_info, qst); + if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + compile_syntax_error(comp, pn, "no binding for nonlocal found"); + } + } else if (id_info->kind != ID_INFO_KIND_FREE) { compile_syntax_error(comp, pn, "identifier redefined as nonlocal"); - return; - } - id_info_t *id_info2 = scope_find_local_in_parent(comp->scope_cur, qst); - if (id_info2 == NULL || !(id_info2->kind == ID_INFO_KIND_LOCAL || id_info2->kind == ID_INFO_KIND_CELL || id_info2->kind == ID_INFO_KIND_FREE)) { - compile_syntax_error(comp, pn, "no binding for nonlocal found"); - return; } - id_info->kind = ID_INFO_KIND_FREE; - scope_close_over_in_parents(comp->scope_cur, qst); } STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1495,6 +1490,8 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ EMIT_ARG(label_assign, l1); // start of exception handler EMIT(start_except_handler); + // at this point the top of the stack contains the exception instance that was raised + uint l2 = comp_next_label(comp); for (int i = 0; i < n_except; i++) { @@ -1528,16 +1525,13 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ EMIT_ARG(pop_jump_if, false, end_finally_label); } - EMIT(pop_top); - + // either discard or store the exception instance if (qstr_exception_local == 0) { EMIT(pop_top); } else { compile_store_id(comp, qstr_exception_local); } - EMIT(pop_top); - uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); @@ -1561,7 +1555,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ } EMIT_ARG(jump, l2); EMIT_ARG(label_assign, end_finally_label); - EMIT_ARG(adjust_stack_size, 3); // stack adjust for the 3 exception items + EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance } compile_decrease_except_level(comp); @@ -1711,14 +1705,12 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration); EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if, false, try_finally_label); - EMIT(pop_top); - EMIT(pop_top); - EMIT(pop_top); + EMIT(pop_top); // pop exception instance EMIT(pop_except); EMIT_ARG(jump, while_else_label); EMIT_ARG(label_assign, try_finally_label); - EMIT_ARG(adjust_stack_size, 3); + EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); @@ -1779,9 +1771,21 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod EMIT_ARG(label_assign, try_exception_label); // start of exception handler EMIT(start_except_handler); - EMIT(rot_three); + + // at this point the stack contains: ..., __aexit__, self, exc + EMIT(dup_top); + #if MICROPY_CPYTHON_COMPAT + EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc) + #else + compile_load_id(comp, MP_QSTR_type); + EMIT(rot_two); + EMIT_ARG(call_function, 1, 0, 0); // get type(exc) + #endif EMIT(rot_two); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // dummy traceback value + // at this point the stack contains: ..., __aexit__, self, type(exc), exc, None EMIT_ARG(call_method, 3, 0, 0); + compile_yield_from(comp); EMIT_ARG(pop_jump_if, true, no_reraise_label); EMIT_ARG(raise_varargs, 0); @@ -1790,7 +1794,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod EMIT(pop_except); EMIT_ARG(jump, end_label); - EMIT_ARG(adjust_stack_size, 5); + EMIT_ARG(adjust_stack_size, 3); // adjust for __aexit__, self, exc compile_decrease_except_level(comp); EMIT(end_finally); EMIT(end_except_handler); @@ -2719,15 +2723,8 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; EMIT_ARG(set_source_line, pns->source_line); compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)]; - if (f == NULL) { -#if MICROPY_DEBUG_PRINTERS - printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns)); - mp_parse_node_print(pn, 0); -#endif - compile_syntax_error(comp, pn, "internal compiler error"); - } else { - f(comp, pns); - } + assert(f != NULL); + f(comp, pns); } } @@ -2832,12 +2829,10 @@ STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) // no annotation return; } - } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star) { + } else { + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star); // double star with possible annotation // fallthrough - } else { - // no annotation - return; } mp_parse_node_t pn_annotation = pns->nodes[1]; @@ -2869,17 +2864,11 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn if (MP_PARSE_NODE_IS_NULL(pn_iter)) { // no more nested if/for; compile inner expression compile_node(comp, pn_inner_expr); - if (comp->scope_cur->kind == SCOPE_LIST_COMP) { - EMIT_ARG(list_append, for_depth + 2); - } else if (comp->scope_cur->kind == SCOPE_DICT_COMP) { - EMIT_ARG(map_add, for_depth + 2); - #if MICROPY_PY_BUILTINS_SET - } else if (comp->scope_cur->kind == SCOPE_SET_COMP) { - EMIT_ARG(set_add, for_depth + 2); - #endif - } else { + if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { EMIT(yield_value); EMIT(pop_top); + } else { + EMIT_ARG(store_comp, comp->scope_cur->kind, for_depth + 2); } } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_iter, PN_comp_if)) { // if condition @@ -3285,7 +3274,7 @@ STATIC void scope_compute_things(scope_t *scope) { // __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL continue; } - if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } // params always count for 1 local, even if they are a cell @@ -119,17 +119,15 @@ typedef struct _emit_method_table_t { void (*binary_op)(emit_t *emit, mp_binary_op_t op); void (*build_tuple)(emit_t *emit, mp_uint_t n_args); void (*build_list)(emit_t *emit, mp_uint_t n_args); - void (*list_append)(emit_t *emit, mp_uint_t list_stack_index); void (*build_map)(emit_t *emit, mp_uint_t n_args); void (*store_map)(emit_t *emit); - void (*map_add)(emit_t *emit, mp_uint_t map_stack_index); #if MICROPY_PY_BUILTINS_SET void (*build_set)(emit_t *emit, mp_uint_t n_args); - void (*set_add)(emit_t *emit, mp_uint_t set_stack_index); #endif #if MICROPY_PY_BUILTINS_SLICE void (*build_slice)(emit_t *emit, mp_uint_t n_args); #endif + void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index); void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args); void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); void (*make_function)(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); @@ -240,17 +238,15 @@ void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_list_append(emit_t *emit, mp_uint_t list_stack_index); void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_store_map(emit_t *emit); -void mp_emit_bc_map_add(emit_t *emit, mp_uint_t map_stack_index); #if MICROPY_PY_BUILTINS_SET void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_set_add(emit_t *emit, mp_uint_t set_stack_index); #endif #if MICROPY_PY_BUILTINS_SLICE void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args); #endif +void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index); void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); diff --git a/py/emitbc.c b/py/emitbc.c index d871aa4ce9..d6f2bf333c 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -302,15 +302,6 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint c[2] = bytecode_offset >> 8; } -#if MICROPY_EMIT_NATIVE -STATIC void mp_emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) { - (void)emit; - (void)op; - (void)arg1; - (void)arg2; -} -#endif - void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->pass = pass; emit->stack_size = 0; @@ -408,9 +399,7 @@ void mp_emit_bc_end_pass(emit_t *emit) { } // check stack is back to zero size - if (emit->stack_size != 0) { - mp_printf(&mp_plat_print, "ERROR: stack size not back to zero; got %d\n", emit->stack_size); - } + assert(emit->stack_size == 0); emit_write_code_info_byte(emit, 0); // end of line number info @@ -528,9 +517,10 @@ void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break; case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break; case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break; - no_other_choice: - case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); break; - default: assert(0); goto no_other_choice; // to help flow control analysis + default: + assert(tok == MP_TOKEN_ELLIPSIS); + emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + break; } } @@ -751,10 +741,9 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept } void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) { - // TODO We can probably optimise the amount of needed stack space, since - // we don't actually need 4 slots during the entire with block, only in - // the cleanup handler in certain cases. It needs some thinking. - emit_bc_pre(emit, 4); + // The SETUP_WITH opcode pops ctx_mgr from the top of the stack + // and then pushes 3 entries: __exit__, ctx_mgr, as_value. + emit_bc_pre(emit, 2); emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label); } @@ -762,8 +751,9 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_pop_block(emit); mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); mp_emit_bc_label_assign(emit, label); - emit_bc_pre(emit, -4); + emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); + emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with } void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) { @@ -837,11 +827,6 @@ void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) { emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args); } -void mp_emit_bc_list_append(emit_t *emit, mp_uint_t list_stack_index) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_uint(emit, MP_BC_LIST_APPEND, list_stack_index); -} - void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args); @@ -852,21 +837,11 @@ void mp_emit_bc_store_map(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); } -void mp_emit_bc_map_add(emit_t *emit, mp_uint_t map_stack_index) { - emit_bc_pre(emit, -2); - emit_write_bytecode_byte_uint(emit, MP_BC_MAP_ADD, map_stack_index); -} - #if MICROPY_PY_BUILTINS_SET void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, 1 - n_args); emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args); } - -void mp_emit_bc_set_add(emit_t *emit, mp_uint_t set_stack_index) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_uint(emit, MP_BC_SET_ADD, set_stack_index); -} #endif #if MICROPY_PY_BUILTINS_SLICE @@ -876,6 +851,24 @@ void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) { } #endif +void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { + int t; + int n; + if (kind == SCOPE_LIST_COMP) { + n = 0; + t = 0; + } else if (!MICROPY_PY_BUILTINS_SET || kind == SCOPE_DICT_COMP) { + n = 1; + t = 1; + } else if (MICROPY_PY_BUILTINS_SET) { + n = 0; + t = 2; + } + emit_bc_pre(emit, -1 - n); + // the lower 2 bits of the opcode argument indicate the collection type + emit_write_bytecode_byte_uint(emit, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); +} + void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) { emit_bc_pre(emit, -1 + n_args); emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args); @@ -952,16 +945,16 @@ void mp_emit_bc_yield_from(emit_t *emit) { } void mp_emit_bc_start_except_handler(emit_t *emit) { - mp_emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state + mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state } void mp_emit_bc_end_except_handler(emit_t *emit) { - mp_emit_bc_adjust_stack_size(emit, -5); // stack adjust + mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust } #if MICROPY_EMIT_NATIVE const emit_method_table_t emit_bc_method_table = { - mp_emit_bc_set_native_type, + NULL, // set_native_type is never called when emitting bytecode mp_emit_bc_start_pass, mp_emit_bc_end_pass, mp_emit_bc_last_emit_was_return_value, @@ -1028,17 +1021,15 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_binary_op, mp_emit_bc_build_tuple, mp_emit_bc_build_list, - mp_emit_bc_list_append, mp_emit_bc_build_map, mp_emit_bc_store_map, - mp_emit_bc_map_add, #if MICROPY_PY_BUILTINS_SET mp_emit_bc_build_set, - mp_emit_bc_set_add, #endif #if MICROPY_PY_BUILTINS_SLICE mp_emit_bc_build_slice, #endif + mp_emit_bc_store_comp, mp_emit_bc_unpack_sequence, mp_emit_bc_unpack_ex, mp_emit_bc_make_function, diff --git a/py/emitcommon.c b/py/emitcommon.c index 435188f366..e914431d32 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -35,13 +35,7 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { bool added; id_info_t *id = scope_find_or_add_id(scope, qst, &added); if (added) { - id_info_t *id2 = scope_find_local_in_parent(scope, qst); - if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) { - id->kind = ID_INFO_KIND_FREE; - scope_close_over_in_parents(scope, qst); - } else { - id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; - } + scope_find_local_and_close_over(scope, id, qst); } } @@ -50,12 +44,12 @@ void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) { bool added; id_info_t *id = scope_find_or_add_id(scope, qst, &added); if (added) { - if (scope->kind == SCOPE_MODULE || scope->kind == SCOPE_CLASS) { - id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; - } else { + if (SCOPE_IS_FUNC_LIKE(scope->kind)) { id->kind = ID_INFO_KIND_LOCAL; + } else { + id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; } - } else if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + } else if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { // rebind as a local variable id->kind = ID_INFO_KIND_LOCAL; } diff --git a/py/emitglue.c b/py/emitglue.c index f544ae2944..e04eb32c91 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -426,7 +426,7 @@ mp_raw_code_t *mp_raw_code_load_file(const char *filename) { return rc; } -#elif defined(__thumb2__) +#elif defined(__thumb2__) || defined(__xtensa__) // fatfs file reader (assume thumb2 arch uses fatfs...) #include "lib/fatfs/ff.h" diff --git a/py/emitnative.c b/py/emitnative.c index 2cf4711feb..b54f263d60 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2344,17 +2344,6 @@ STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list } -STATIC void emit_native_list_append(emit_t *emit, mp_uint_t list_index) { - // only used in list comprehension - vtype_kind_t vtype_list, vtype_item; - emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); - emit_access_stack(emit, list_index, &vtype_list, REG_ARG_1); - assert(vtype_list == VTYPE_PYOBJ); - assert(vtype_item == VTYPE_PYOBJ); - emit_call(emit, MP_F_LIST_APPEND); - emit_post(emit); -} - STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) { emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1); @@ -2371,18 +2360,6 @@ STATIC void emit_native_store_map(emit_t *emit) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map } -STATIC void emit_native_map_add(emit_t *emit, mp_uint_t map_index) { - // only used in list comprehension - vtype_kind_t vtype_map, vtype_key, vtype_value; - emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3); - emit_access_stack(emit, map_index, &vtype_map, REG_ARG_1); - assert(vtype_map == VTYPE_PYOBJ); - assert(vtype_key == VTYPE_PYOBJ); - assert(vtype_value == VTYPE_PYOBJ); - emit_call(emit, MP_F_STORE_MAP); - emit_post(emit); -} - #if MICROPY_PY_BUILTINS_SET STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) { emit_native_pre(emit); @@ -2390,17 +2367,6 @@ STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) { emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set } - -STATIC void emit_native_set_add(emit_t *emit, mp_uint_t set_index) { - // only used in set comprehension - vtype_kind_t vtype_set, vtype_item; - emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); - emit_access_stack(emit, set_index, &vtype_set, REG_ARG_1); - assert(vtype_set == VTYPE_PYOBJ); - assert(vtype_item == VTYPE_PYOBJ); - emit_call(emit, MP_F_STORE_SET); - emit_post(emit); -} #endif #if MICROPY_PY_BUILTINS_SLICE @@ -2426,6 +2392,35 @@ STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { } #endif +STATIC void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_index) { + mp_fun_kind_t f; + if (kind == SCOPE_LIST_COMP) { + vtype_kind_t vtype_item; + emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); + assert(vtype_item == VTYPE_PYOBJ); + f = MP_F_LIST_APPEND; + #if MICROPY_PY_BUILTINS_SET + } else if (kind == SCOPE_SET_COMP) { + vtype_kind_t vtype_item; + emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); + assert(vtype_item == VTYPE_PYOBJ); + f = MP_F_STORE_SET; + #endif + } else { + // SCOPE_DICT_COMP + vtype_kind_t vtype_key, vtype_value; + emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3); + assert(vtype_key == VTYPE_PYOBJ); + assert(vtype_value == VTYPE_PYOBJ); + f = MP_F_STORE_MAP; + } + vtype_kind_t vtype_collection; + emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1); + assert(vtype_collection == VTYPE_PYOBJ); + emit_call(emit, f); + emit_post(emit); +} + STATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("unpack_sequence %d\n", n_args); vtype_kind_t vtype_base; @@ -2674,17 +2669,15 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_binary_op, emit_native_build_tuple, emit_native_build_list, - emit_native_list_append, emit_native_build_map, emit_native_store_map, - emit_native_map_add, #if MICROPY_PY_BUILTINS_SET emit_native_build_set, - emit_native_set_add, #endif #if MICROPY_PY_BUILTINS_SLICE emit_native_build_slice, #endif + emit_native_store_comp, emit_native_unpack_sequence, emit_native_unpack_ex, emit_native_make_function, diff --git a/py/lexer.c b/py/lexer.c index 820f91be78..4a7c8f580a 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -343,7 +343,6 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) { lex->tok_kind = MP_TOKEN_NEWLINE; mp_uint_t num_spaces = lex->column - 1; - lex->emit_dent = 0; if (num_spaces == indent_top(lex)) { } else if (num_spaces > indent_top(lex)) { indent_push(lex, num_spaces); @@ -359,16 +358,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) { } } else if (is_end(lex)) { - if (indent_top(lex) > 0) { - lex->tok_kind = MP_TOKEN_NEWLINE; - lex->emit_dent = 0; - while (indent_top(lex) > 0) { - indent_pop(lex); - lex->emit_dent -= 1; - } - } else { - lex->tok_kind = MP_TOKEN_END; - } + lex->tok_kind = MP_TOKEN_END; } else if (is_char_or(lex, '\'', '\"') || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"')) @@ -723,7 +713,8 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_ vstr_init(&lex->vstr, 32); // check for memory allocation error - if (lex->indent_level == NULL || vstr_had_error(&lex->vstr)) { + // note: vstr_init above may fail on malloc, but so may mp_lexer_next_token_into below + if (lex->indent_level == NULL) { mp_lexer_free(lex); return NULL; } diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 69aaefb3e6..92a19c3920 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -11,7 +11,7 @@ import os # Blacklist of qstrings that are specially handled in further # processing and should be ignored -QSTRING_BLACK_LIST = {'NULL', 'number_of', } +QSTRING_BLACK_LIST = set(['NULL', 'number_of']) def write_out(fname, output): @@ -139,7 +139,6 @@ typedef struct _vstr_t { size_t alloc; size_t len; char *buf; - bool had_error : 1; bool fixed_buf : 1; } vstr_t; @@ -152,13 +151,11 @@ void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf); struct _mp_print_t; void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print); void vstr_clear(vstr_t *vstr); -vstr_t *vstr_new(void); -vstr_t *vstr_new_size(size_t alloc); +vstr_t *vstr_new(size_t alloc); void vstr_free(vstr_t *vstr); -void vstr_reset(vstr_t *vstr); -bool vstr_had_error(vstr_t *vstr); -char *vstr_str(vstr_t *vstr); -size_t vstr_len(vstr_t *vstr); +static inline void vstr_reset(vstr_t *vstr) { vstr->len = 0; } +static inline char *vstr_str(vstr_t *vstr) { return vstr->buf; } +static inline size_t vstr_len(vstr_t *vstr) { return vstr->len; } void vstr_hint_size(vstr_t *vstr, size_t size); char *vstr_extend(vstr_t *vstr, size_t size); char *vstr_add_len(vstr_t *vstr, size_t len); diff --git a/py/mkenv.mk b/py/mkenv.mk index b7f8c2aff4..e7262907c8 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -58,6 +58,8 @@ CXX += -m32 LD += -m32 endif +MAKE_FROZEN = ../tools/make-frozen.py + all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index a3a408dc89..26e4aeab3f 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -100,6 +100,12 @@ $(OBJ_DIRS): $(HEADER_BUILD): $(MKDIR) -p $@ +ifneq ($(FROZEN_DIR),) +$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) + $(ECHO) "Generating $@" + $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ +endif + ifneq ($(PROG),) # Build a standalone executable (unix does this) diff --git a/py/modarray.c b/py/modarray.c index cfee011e10..356e48bee0 100644 --- a/py/modarray.c +++ b/py/modarray.c @@ -37,7 +37,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_tab const mp_obj_module_t mp_module_array = { .base = { &mp_type_module }, - .name = MP_QSTR_array, .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; diff --git a/py/modbuiltins.c b/py/modbuiltins.c index ac3d3041f5..57e52efa52 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -178,7 +178,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { str[3] = (c & 0x3F) | 0x80; len = 4; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); + mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"); } return mp_obj_new_str(str, len, true); #else @@ -187,7 +187,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { char str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(256)")); + mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(256)"); } #endif } @@ -286,7 +286,7 @@ STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t if (default_elem != NULL) { best_obj = default_elem->value; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence")); + mp_raise_msg(&mp_type_ValueError, "arg is an empty sequence"); } } return best_obj; @@ -507,8 +507,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args > 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "must use keyword argument for key function")); + mp_raise_msg(&mp_type_TypeError, "must use keyword argument for key function"); } mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); mp_obj_list_sort(1, &self, kwargs); @@ -577,6 +576,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id); MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len); STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_builtins) }, + // built-in core functions { MP_ROM_QSTR(MP_QSTR___build_class__), MP_ROM_PTR(&mp_builtin___build_class___obj) }, { MP_ROM_QSTR(MP_QSTR___import__), MP_ROM_PTR(&mp_builtin___import___obj) }, @@ -727,6 +728,5 @@ MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_tabl const mp_obj_module_t mp_module_builtins = { .base = { &mp_type_module }, - .name = MP_QSTR_builtins, .globals = (mp_obj_dict_t*)&mp_module_builtins_globals, }; diff --git a/py/modcmath.c b/py/modcmath.c index 33fe9c73f5..7ad8f5ad60 100644 --- a/py/modcmath.c +++ b/py/modcmath.c @@ -160,7 +160,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_cmath_globals, mp_module_cmath_globals_tab const mp_obj_module_t mp_module_cmath = { .base = { &mp_type_module }, - .name = MP_QSTR_cmath, .globals = (mp_obj_dict_t*)&mp_module_cmath_globals, }; diff --git a/py/modcollections.c b/py/modcollections.c index dceaa203de..e610a28d24 100644 --- a/py/modcollections.c +++ b/py/modcollections.c @@ -40,7 +40,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections const mp_obj_module_t mp_module_collections = { .base = { &mp_type_module }, - .name = MP_QSTR_ucollections, .globals = (mp_obj_dict_t*)&mp_module_collections_globals, }; diff --git a/py/modgc.c b/py/modgc.c index 976fb89980..24564622ec 100644 --- a/py/modgc.c +++ b/py/modgc.c @@ -119,7 +119,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table); const mp_obj_module_t mp_module_gc = { .base = { &mp_type_module }, - .name = MP_QSTR_gc, .globals = (mp_obj_dict_t*)&mp_module_gc_globals, }; diff --git a/py/modio.c b/py/modio.c index f8826c71a7..d5da0b1db7 100644 --- a/py/modio.c +++ b/py/modio.c @@ -102,7 +102,7 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { assert(out_sz == self->len); self->len = 0; if (err != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); + mp_raise_OSError(err); } } @@ -153,7 +153,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table); const mp_obj_module_t mp_module_io = { .base = { &mp_type_module }, - .name = MP_QSTR_uio, .globals = (mp_obj_dict_t*)&mp_module_io_globals, }; diff --git a/py/modmath.c b/py/modmath.c index 54262f6115..0c70f34cd1 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -268,7 +268,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table const mp_obj_module_t mp_module_math = { .base = { &mp_type_module }, - .name = MP_QSTR_math, .globals = (mp_obj_dict_t*)&mp_module_math_globals, }; diff --git a/py/modmicropython.c b/py/modmicropython.c index 805bda51d2..675d169cc4 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -34,6 +34,16 @@ // Various builtins specific to MicroPython runtime, // living in micropython module +STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); + } else { + MP_STATE_VM(mp_optimise_value) = mp_obj_get_int(args[0]); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); + #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS @@ -120,6 +130,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, + { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, @@ -145,6 +157,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython const mp_obj_module_t mp_module_micropython = { .base = { &mp_type_module }, - .name = MP_QSTR_micropython, .globals = (mp_obj_dict_t*)&mp_module_micropython_globals, }; diff --git a/py/modstruct.c b/py/modstruct.c index be0d0110de..88411ff0fc 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -156,9 +156,6 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { } for (uint i = 0; i < num_items;) { - if (*fmt == '\0') { - break; - } mp_uint_t sz = 1; if (unichar_isdigit(*fmt)) { sz = get_fmt_num(&fmt); @@ -191,6 +188,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, siz for (i = 0; i < n_args;) { mp_uint_t sz = 1; if (*fmt == '\0') { + // more arguments given than used by format string; CPython raises struct.error here break; } if (unichar_isdigit(*fmt)) { @@ -265,7 +263,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_t const mp_obj_module_t mp_module_ustruct = { .base = { &mp_type_module }, - .name = MP_QSTR_ustruct, .globals = (mp_obj_dict_t*)&mp_module_struct_globals, }; diff --git a/py/modsys.c b/py/modsys.c index 3bc5c2bafc..8c368ac35b 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -203,7 +203,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); const mp_obj_module_t mp_module_sys = { .base = { &mp_type_module }, - .name = MP_QSTR_sys, .globals = (mp_obj_dict_t*)&mp_module_sys_globals, }; diff --git a/py/modthread.c b/py/modthread.c index 6c8340c928..6f55281adc 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -93,7 +93,7 @@ STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) { self->locked = true; return mp_const_true; } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-ret))); + mp_raise_OSError(-ret); } #endif } @@ -239,7 +239,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) } else { // positional and keyword arguments if (mp_obj_get_type(args[2]) != &mp_type_dict) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting a dict for keyword args")); + mp_raise_msg(&mp_type_TypeError, "expecting a dict for keyword args"); } mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); @@ -294,7 +294,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_t const mp_obj_module_t mp_module_thread = { .base = { &mp_type_module }, - .name = MP_QSTR__thread, .globals = (mp_obj_dict_t*)&mp_module_thread_globals, }; diff --git a/py/moduerrno.c b/py/moduerrno.c index 343b29ba08..4a5e87419f 100644 --- a/py/moduerrno.c +++ b/py/moduerrno.c @@ -89,7 +89,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_t 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, }; diff --git a/py/mpconfig.h b/py/mpconfig.h index e33a41f7a0..dcdaffe0f4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -860,6 +860,12 @@ typedef double mp_float_t; #define MICROPY_PY_UERRNO (0) #endif +// Whether to provide "utime" module functions implementation +// in terms of mp_hal_* functions. +#ifndef MICROPY_PY_UTIME_MP_HAL +#define MICROPY_PY_UTIME_MP_HAL (0) +#endif + // Whether to provide "_thread" module #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (0) diff --git a/py/mphal.h b/py/mphal.h index 54a45b0240..8d5654f9e3 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -66,6 +66,10 @@ mp_uint_t mp_hal_ticks_ms(void); mp_uint_t mp_hal_ticks_us(void); #endif +#ifndef mp_hal_ticks_cpu +mp_uint_t mp_hal_ticks_cpu(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 diff --git a/py/mpprint.c b/py/mpprint.c index 97ea33ad2a..9ad0f3f9a0 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -252,8 +252,8 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char // enough, a dynamic one will be allocated. char stack_buf[sizeof(mp_int_t) * 4]; char *buf = stack_buf; - mp_uint_t buf_size = sizeof(stack_buf); - mp_uint_t fmt_size = 0; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size = 0; char *str; if (prec > 1) { @@ -645,18 +645,6 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, const mpz_dig_t *den #define MIN_ALLOC (2) -STATIC const uint8_t log_base2_floor[] = { - 0, - 0, 1, 1, 2, - 2, 2, 2, 3, - 3, 3, 3, 3, - 3, 3, 3, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 5 -}; - void mpz_init_zero(mpz_t *z) { z->neg = 0; z->fixed_dig = 0; @@ -734,11 +722,9 @@ STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) { } if (z->dig == NULL || z->alloc < need) { - if (z->fixed_dig) { - // cannot reallocate fixed buffers - assert(0); - return; - } + // if z has fixed digit buffer there's not much we can do as the caller will + // be expecting a buffer with at least "need" bytes (but it shouldn't happen) + assert(!z->fixed_dig); z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need); z->alloc = need; } @@ -1497,13 +1483,10 @@ mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) { quo * rhs + rem = lhs 0 <= rem < rhs can have lhs, rhs the same + assumes rhs != 0 (undefined behaviour if it is) */ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) { - if (rhs->len == 0) { - mpz_set_from_int(dest_quo, 0); - mpz_set_from_int(dest_rem, 0); - return; - } + assert(!mpz_is_zero(rhs)); mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary? memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t)); @@ -1657,18 +1640,6 @@ mp_float_t mpz_as_float(const mpz_t *i) { } #endif -mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma) { - if (base < 2 || base > 32) { - return 0; - } - - mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1; - mp_uint_t num_commas = comma ? num_digits / 3: 0; - mp_uint_t prefix_len = prefix ? strlen(prefix) : 0; - - return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte -} - #if 0 this function is unused char *mpz_as_str(const mpz_t *i, mp_uint_t base) { @@ -1678,7 +1649,7 @@ char *mpz_as_str(const mpz_t *i, mp_uint_t base) { } #endif -// assumes enough space as calculated by mpz_as_str_size +// assumes enough space as calculated by mp_int_format_size // returns length of string, not including null byte mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) { if (str == NULL || base < 2 || base > 32) { @@ -127,6 +127,7 @@ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); +static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; } mp_int_t mpz_hash(const mpz_t *z); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); @@ -233,8 +233,7 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return mp_obj_int_get_checked(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to int")); + mp_raise_msg(&mp_type_TypeError, "can't convert to int"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); @@ -282,8 +281,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { return mp_obj_float_get(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to float")); + mp_raise_msg(&mp_type_TypeError, "can't convert to float"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); @@ -312,8 +310,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to complex")); + mp_raise_msg(&mp_type_TypeError, "can't convert to complex"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); @@ -331,8 +328,7 @@ void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { mp_obj_list_get(o, len, items); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "expected tuple/list")); + mp_raise_msg(&mp_type_TypeError, "expected tuple/list"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); @@ -346,8 +342,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { mp_obj_get_array(o, &seq_len, items); if (seq_len != len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "tuple/list has wrong length")); + mp_raise_msg(&mp_type_ValueError, "tuple/list has wrong length"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", (int)len, (int)seq_len)); @@ -362,8 +357,7 @@ mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "indices must be integers")); + mp_raise_msg(&mp_type_TypeError, "indices must be integers"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", @@ -383,7 +377,7 @@ mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, } else { if (i < 0 || (mp_uint_t)i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "index out of range")); + mp_raise_msg(&mp_type_IndexError, "index out of range"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%q index out of range", type->name)); @@ -416,8 +410,7 @@ mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object has no len")); + mp_raise_msg(&mp_type_TypeError, "object has no len"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); @@ -458,8 +451,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } if (value == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object does not support item deletion")); + mp_raise_msg(&mp_type_TypeError, "object does not support item deletion"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); @@ -474,8 +466,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object does not support item assignment")); + mp_raise_msg(&mp_type_TypeError, "object does not support item assignment"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); @@ -504,7 +495,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (!mp_get_buffer(obj, bufinfo, flags)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "object with buffer protocol required")); + mp_raise_msg(&mp_type_TypeError, "object with buffer protocol required"); } } @@ -765,7 +765,6 @@ MP_DECLARE_CONST_FUN_OBJ(mp_identity_obj); // module typedef struct _mp_obj_module_t { mp_obj_base_t base; - qstr name; mp_obj_dict_t *globals; } mp_obj_module_t; mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t self_in); diff --git a/py/objarray.c b/py/objarray.c index 2cd0fef6b6..8e1d32f0f4 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -95,7 +95,7 @@ STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) { int typecode_size = mp_binary_get_size('@', typecode, NULL); if (typecode_size == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode")); + mp_raise_msg(&mp_type_ValueError, "bad typecode"); } mp_obj_array_t *o = m_new_obj(mp_obj_array_t); #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY @@ -395,7 +395,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { compat_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "lhs and rhs should be compatible")); + mp_raise_msg(&mp_type_ValueError, "lhs and rhs should be compatible"); } src_len = src_slice->len; src_items = src_slice->items; diff --git a/py/objbool.c b/py/objbool.c index 8882a835d3..5bc04bb6f9 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -56,26 +56,19 @@ STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ (void)type_in; mp_arg_check_num(n_args, n_kw, 0, 1, false); - switch (n_args) { - case 0: - return mp_const_false; - case 1: - default: // must be 0 or 1 - if (mp_obj_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; } + if (n_args == 0) { + return mp_const_false; + } else { + return mp_obj_new_bool(mp_obj_is_true(args[0])); } } STATIC mp_obj_t bool_unary_op(mp_uint_t op, mp_obj_t o_in) { - mp_int_t value = ((mp_obj_bool_t*)MP_OBJ_TO_PTR(o_in))->value; - switch (op) { - case MP_UNARY_OP_BOOL: return o_in; - // needs to hash to the same value as if converting to an integer - case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(value); - case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value); - case MP_UNARY_OP_NEGATIVE: return MP_OBJ_NEW_SMALL_INT(-value); - case MP_UNARY_OP_INVERT: return MP_OBJ_NEW_SMALL_INT(~value); - default: return MP_OBJ_NULL; // op not supported + if (op == MP_UNARY_OP_LEN) { + return MP_OBJ_NULL; } + mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in); + return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value)); } STATIC mp_obj_t bool_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { diff --git a/py/objcomplex.c b/py/objcomplex.c index 5da655eb3c..96be25255c 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -197,7 +197,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_imag == 0) { if (rhs_real == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "complex division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "complex division by zero"); } lhs_real /= rhs_real; lhs_imag /= rhs_real; @@ -226,7 +226,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_real = 1; rhs_real = 0; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power")); + mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"); } } else { mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); diff --git a/py/objdict.c b/py/objdict.c index 7a74557dc1..4942d37791 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -162,7 +162,7 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } @@ -178,7 +178,7 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } @@ -250,15 +250,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); // this is a classmethod STATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) { mp_obj_t iter = mp_getiter(args[1]); - mp_obj_t len = mp_obj_len_maybe(iter); mp_obj_t value = mp_const_none; mp_obj_t next = MP_OBJ_NULL; - mp_obj_t self_out; if (n_args > 2) { value = args[2]; } + // optimisation to allocate result based on len of argument + mp_obj_t self_out; + mp_obj_t len = mp_obj_len_maybe(args[1]); if (len == MP_OBJ_NULL) { /* object's type doesn't have a __len__ slot */ self_out = mp_obj_new_dict(0); @@ -282,7 +283,7 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp if (elem == NULL || elem->value == MP_OBJ_NULL) { if (deflt == MP_OBJ_NULL) { if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, key)); } else { value = mp_const_none; } @@ -342,7 +343,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_uint_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty")); + mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty"); } self->map.used--; mp_obj_t items[] = {next->key, next->value}; @@ -384,9 +385,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg if (key == MP_OBJ_STOP_ITERATION || value == MP_OBJ_STOP_ITERATION || stop != MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception_msg( - &mp_type_ValueError, - "dictionary update sequence has the wrong length")); + mp_raise_msg(&mp_type_ValueError, "dictionary update sequence has the wrong length"); } else { mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } diff --git a/py/objfloat.c b/py/objfloat.c index 85b8b13861..73d07feac8 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -198,7 +198,7 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { zero_division_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } // Python specs require that x == (x//y)*y + (x%y) so we must // call divmod to compute the correct floor division, which diff --git a/py/objfun.c b/py/objfun.c index 3fd25fb224..405f38127a 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -266,23 +266,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const #endif mp_obj_t result; - switch (vm_return_kind) { - case MP_VM_RETURN_NORMAL: - // return value is in *sp - result = *code_state->sp; - break; - - case MP_VM_RETURN_EXCEPTION: - // return value is in state[n_state - 1] - result = code_state->state[n_state - 1]; - break; - - case MP_VM_RETURN_YIELD: // byte-code shouldn't yield - default: - assert(0); - result = mp_const_none; - vm_return_kind = MP_VM_RETURN_NORMAL; - break; + if (vm_return_kind == MP_VM_RETURN_NORMAL) { + // return value is in *sp + result = *code_state->sp; + } else { + // must be an exception because normal functions can't yield + assert(vm_return_kind == MP_VM_RETURN_EXCEPTION); + // return value is in fastn[0]==state[n_state - 1] + result = code_state->state[n_state - 1]; } // free the state if it was allocated on the heap @@ -409,17 +400,15 @@ STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, con ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8)); } else if (n_args == 3) { ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8), mp_convert_obj_to_native(args[2], self->type_sig >> 12)); - } else if (n_args == 4) { + } else { + // compiler allows at most 4 arguments + assert(n_args == 4); ret = ((viper_fun_4_t)fun)( mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8), mp_convert_obj_to_native(args[2], self->type_sig >> 12), mp_convert_obj_to_native(args[3], self->type_sig >> 16) ); - } else { - // TODO 5 or more arguments not supported for viper call - assert(0); - ret = 0; } return mp_convert_native_to_obj(ret, self->type_sig); diff --git a/py/objgenerator.c b/py/objgenerator.c index 8c32a36496..cbef9fea3d 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -105,7 +105,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator")); + mp_raise_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator"); } } else { *self->code_state.sp = send_value; @@ -157,7 +157,7 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o case MP_VM_RETURN_YIELD: if (throw_value != MP_OBJ_NULL && mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(throw_value)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); } return ret; @@ -209,7 +209,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { case MP_VM_RETURN_YIELD: - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other case MP_VM_RETURN_EXCEPTION: diff --git a/py/objint.c b/py/objint.c index 9f948a1455..f8988d6c94 100644 --- a/py/objint.c +++ b/py/objint.c @@ -133,8 +133,8 @@ void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t // enough, a dynamic one will be allocated. char stack_buf[sizeof(mp_int_t) * 4]; char *buf = stack_buf; - mp_uint_t buf_size = sizeof(stack_buf); - mp_uint_t fmt_size; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size; char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0'); mp_print_str(print, str); @@ -162,14 +162,14 @@ STATIC const uint8_t log_base2_floor[] = { 4, 4, 4, 5 }; -STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { if (base < 2 || base > 32) { return 0; } - uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1; - uint num_commas = comma ? num_digits / 3: 0; - uint prefix_len = prefix ? strlen(prefix) : 0; + size_t num_digits = num_bits / log_base2_floor[base] + 1; + size_t num_commas = comma ? num_digits / 3 : 0; + size_t prefix_len = prefix ? strlen(prefix) : 0; return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } @@ -180,7 +180,7 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. -char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { fmt_int_t num; if (MP_OBJ_IS_SMALL_INT(self_in)) { @@ -211,7 +211,7 @@ char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, sign = '-'; } - uint needed_size = int_as_str_size_formatted(base, prefix, comma); + size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; @@ -294,19 +294,19 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // This is called only with strings whose value doesn't fit in SMALL_INT mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build")); + mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ll(long long val) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } @@ -316,7 +316,7 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } @@ -342,7 +342,7 @@ mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } diff --git a/py/objint.h b/py/objint.h index c79eb874a9..6e627f1bd7 100644 --- a/py/objint.h +++ b/py/objint.h @@ -50,13 +50,15 @@ typedef enum { mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val); #endif // MICROPY_PY_BUILTINS_FLOAT +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); -char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); -char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); mp_int_t mp_obj_int_hash(mp_obj_t self_in); -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf); +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_abs(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index f10e46447b..b051cfbe64 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -53,7 +53,7 @@ const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf) { +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 3a30eb9d9b..0a1d68598d 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -90,12 +90,12 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { // formatted size will be in *fmt_size. // // This particular routine should only be called for the mpz representation of the int. -char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); - mp_uint_t needed_size = mpz_as_str_size(&self->mpz, base, prefix, comma); + size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; @@ -107,7 +107,7 @@ char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_ return str; } -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf) { +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mpz_as_bytes(&self->mpz, big_endian, len, buf); @@ -234,8 +234,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { if (mpz_is_zero(zrhs)) { zero_division_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, - "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); @@ -272,7 +271,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_RSHIFT: { mp_int_t irhs = mp_obj_int_get_checked(rhs_in); if (irhs < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); @@ -398,7 +397,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return value; } else { // overflow - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "overflow converting long int to machine word")); + mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); } } } diff --git a/py/objlist.c b/py/objlist.c index b5e8b99651..6d4a20a507 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -266,7 +266,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "pop from empty list")); + mp_raise_msg(&mp_type_IndexError, "pop from empty list"); } mp_uint_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; diff --git a/py/objmodule.c b/py/objmodule.c index dc2ce787b4..9b06e3b7b5 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -37,17 +37,23 @@ STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); + const char *module_name = ""; + mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP); + if (elem != NULL) { + module_name = mp_obj_str_get_str(elem->value); + } + #if MICROPY_PY___FILE__ // If we store __file__ to imported modules then try to lookup this // symbol to give more information about the module. - mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); + elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); if (elem != NULL) { - mp_printf(print, "<module '%q' from '%s'>", self->name, mp_obj_str_get_str(elem->value)); + mp_printf(print, "<module '%s' from '%s'>", module_name, mp_obj_str_get_str(elem->value)); return; } #endif - mp_printf(print, "<module '%q'>", self->name); + mp_printf(print, "<module '%s'>", module_name); } STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { @@ -106,7 +112,6 @@ mp_obj_t mp_obj_new_module(qstr module_name) { // create new module object mp_obj_module_t *o = m_new_obj(mp_obj_module_t); o->base.type = &mp_type_module; - o->name = module_name; o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE)); // store __name__ entry in the module diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 38cda1ad75..18931a16c2 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -73,7 +73,7 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } else { // delete/store attribute // provide more detailed error message than we'd get by just returning - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); + mp_raise_msg(&mp_type_AttributeError, "can't set attribute"); } } diff --git a/py/objnone.c b/py/objnone.c index 69eab03fe2..5d5b83540d 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -43,20 +43,11 @@ STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ } } -STATIC mp_obj_t none_unary_op(mp_uint_t op, mp_obj_t o_in) { - (void)o_in; - switch (op) { - case MP_UNARY_OP_BOOL: return mp_const_false; - case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); - default: return MP_OBJ_NULL; // op not supported - } -} - const mp_obj_type_t mp_type_NoneType = { { &mp_type_type }, .name = MP_QSTR_NoneType, .print = none_print, - .unary_op = none_unary_op, + .unary_op = mp_generic_unary_op, }; const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}}; diff --git a/py/objobject.c b/py/objobject.c index bba6f053e6..b33dc491c4 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -50,8 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "__new__ arg must be a user-type")); + mp_raise_msg(&mp_type_TypeError, "__new__ arg must be a user-type"); } mp_obj_t o = MP_OBJ_SENTINEL; mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); diff --git a/py/objset.c b/py/objset.c index fb89c07f3d..fc124fcd8c 100644 --- a/py/objset.c +++ b/py/objset.c @@ -57,27 +57,21 @@ STATIC bool is_set_or_frozenset(mp_obj_t o) { ; } -#if MICROPY_PY_BUILTINS_FROZENSET -STATIC void check_set_or_frozenset(mp_obj_t o) { - if (!is_set_or_frozenset(o)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required")); - } -} -#else -#define check_set_or_frozenset(o) check_set(o) -#endif +// This macro is shorthand for mp_check_self to verify the argument is a +// set or frozenset for methods that operate on both of these types. +#define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o)) +// This function is used to verify the argument for methods that modify +// the set object, and raises an exception if the arg is a frozenset. STATIC void check_set(mp_obj_t o) { - if (!MP_OBJ_IS_TYPE(o, &mp_type_set)) { - // Emulate CPython behavior + #if MICROPY_PY_BUILTINS_FROZENSET + if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) { + // Mutable method called on frozenset; emulate CPython behavior, eg: // AttributeError: 'frozenset' object has no attribute 'add' - #if MICROPY_PY_BUILTINS_FROZENSET - if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute")); - } - #endif - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required")); + mp_raise_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"); } + #endif + mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)); } STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -395,7 +389,7 @@ STATIC mp_obj_t set_pop(mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t obj = mp_set_remove_first(&self->set); if (obj == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "pop from an empty set")); + mp_raise_msg(&mp_type_KeyError, "pop from an empty set"); } return obj; } @@ -441,6 +435,7 @@ STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) { } STATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) { + check_set(args[0]); for (mp_uint_t i = 1; i < n_args; i++) { set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]); } diff --git a/py/objstr.c b/py/objstr.c index 406ccf290a..f082e95591 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -881,9 +881,14 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) { return arg; } +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE STATIC NORETURN void terse_str_format_value_error(void) { mp_raise_ValueError("bad format string"); } +#else +// define to nothing to improve coverage +#define terse_str_format_value_error() +#endif STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { vstr_t vstr; diff --git a/py/objstringio.c b/py/objstringio.c index eb2e516bb3..a430fca3b7 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -30,22 +30,16 @@ #include "py/nlr.h" #include "py/objstr.h" +#include "py/objstringio.h" #include "py/runtime.h" #include "py/stream.h" #if MICROPY_PY_IO -typedef struct _mp_obj_stringio_t { - mp_obj_base_t base; - vstr_t *vstr; - // StringIO has single pointer used for both reading and writing - mp_uint_t pos; -} mp_obj_stringio_t; - #if MICROPY_CPYTHON_COMPAT STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); } } #else @@ -156,7 +150,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); o->base.type = type; - o->vstr = vstr_new(); + o->vstr = vstr_new(16); o->pos = 0; return o; } @@ -177,7 +171,7 @@ STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, s STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, diff --git a/py/objstringio.h b/py/objstringio.h new file mode 100644 index 0000000000..853bfb11b7 --- /dev/null +++ b/py/objstringio.h @@ -0,0 +1,38 @@ +/* + * 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_OBJSTRINGIO_H +#define MICROPY_INCLUDED_PY_OBJSTRINGIO_H + +#include "py/obj.h" + +typedef struct _mp_obj_stringio_t { + mp_obj_base_t base; + vstr_t *vstr; + // StringIO has single pointer used for both reading and writing + mp_uint_t pos; +} mp_obj_stringio_t; + +#endif // MICROPY_INCLUDED_PY_OBJSTRINGIO_H diff --git a/py/objtype.c b/py/objtype.c index 907308a757..8b46c54001 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -311,8 +311,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } if (init_ret != mp_const_none) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "__init__() should return None")); + mp_raise_msg(&mp_type_TypeError, "__init__() should return None"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); @@ -508,7 +507,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // the code. const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "unreadable attribute")); + mp_raise_msg(&mp_type_AttributeError, "unreadable attribute"); } else { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); } @@ -710,8 +709,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_t call = mp_obj_instance_get_call(self_in); if (call == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not callable")); + mp_raise_msg(&mp_type_TypeError, "object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in))); @@ -793,7 +791,7 @@ STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments")); + mp_raise_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"); } } @@ -804,7 +802,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (self->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "cannot create instance")); + mp_raise_msg(&mp_type_TypeError, "cannot create instance"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%q' instances", self->name)); @@ -892,8 +890,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "type is not an acceptable base type")); + mp_raise_msg(&mp_type_TypeError, "type is not an acceptable base type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "type '%q' is not an acceptable base type", t->name)); @@ -927,7 +924,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) const mp_obj_type_t *native_base; uint num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict")); + mp_raise_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"); } mp_map_t *locals_map = &o->locals_dict->map; @@ -1074,7 +1071,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes")); + mp_raise_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"); } for (uint i = 0; i < len; i++) { @@ -1088,7 +1085,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class")); + mp_raise_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); } diff --git a/py/parse.c b/py/parse.c index 1ec995cd8f..5920828fe9 100644 --- a/py/parse.c +++ b/py/parse.c @@ -398,21 +398,24 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, return (mp_parse_node_t)pn; } -STATIC void push_result_token(parser_t *parser) { +STATIC void push_result_token(parser_t *parser, const rule_t *rule) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len); #if MICROPY_COMP_CONST - // lookup identifier in table of dynamic constants - mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP); - if (elem != NULL) { + // if name is a standalone identifier, look it up in the table of dynamic constants + mp_map_elem_t *elem; + if (rule->rule_id == RULE_atom + && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(elem->value)); - } else - #endif - { + } else { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } + #else + (void)rule; + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); + #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { @@ -765,7 +768,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { - push_result_token(&parser); + push_result_token(&parser, rule); mp_lexer_to_next(lex); goto next_rule; } @@ -810,7 +813,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { - push_result_token(&parser); + push_result_token(&parser, rule); } mp_lexer_to_next(lex); } else { @@ -950,7 +953,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack } else { - push_result_token(&parser); + push_result_token(&parser, rule); } mp_lexer_to_next(lex); // got element of list, so continue parsing list diff --git a/py/parsenum.c b/py/parsenum.c index 83a6abd202..1010ad3055 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -27,7 +27,7 @@ #include <stdbool.h> #include <stdlib.h> -#include "py/nlr.h" +#include "py/runtime.h" #include "py/parsenumbase.h" #include "py/parsenum.h" #include "py/smallint.h" @@ -55,7 +55,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m // check radix base if ((base != 0 && base < 2) || base > 36) { // this won't be reached if lex!=NULL - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36")); + mp_raise_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36"); } // skip leading space @@ -24,6 +24,11 @@ CFLAGS_MOD += -DMICROPY_PY_USSL=1 ifeq ($(MICROPY_SSL_AXTLS),1) CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I../lib/axtls/ssl -I../lib/axtls/crypto -I../lib/axtls/config LDFLAGS_MOD += -Lbuild -laxtls +else ifeq ($(MICROPY_SSL_MBEDTLS),1) +# Can be overriden by ports which have "builtin" mbedTLS +MICROPY_SSL_MBEDTLS_INCLUDE ?= ../lib/mbedtls/include +CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) +LDFLAGS_MOD += -L../lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto endif endif @@ -89,6 +94,8 @@ btree/bt_utils.c \ mpool/mpool.c \ ) CFLAGS_MOD += -DMICROPY_PY_BTREE=1 +# we need to suppress certain warnings to get berkeley-db to compile cleanly +$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter endif # py object files @@ -210,6 +217,7 @@ PY_O_BASENAME = \ ../extmod/machine_i2c.o \ ../extmod/machine_spi.o \ ../extmod/modussl_axtls.o \ + ../extmod/modussl_mbedtls.o \ ../extmod/modurandom.o \ ../extmod/modwebsocket.o \ ../extmod/modwebrepl.o \ @@ -221,6 +229,7 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_file.o \ ../extmod/vfs_fat_lexer.o \ ../extmod/vfs_fat_misc.o \ + ../extmod/utime_mphal.o \ ../extmod/moduos_dupterm.o \ ../lib/embed/abort_.o \ ../lib/utils/printf.o \ @@ -275,7 +275,6 @@ size_t qstr_len(qstr q) { return Q_GET_LENGTH(qd); } -// XXX to remove! const char *qstr_str(qstr q) { const byte *qd = find_qstr(q); return (const char*)Q_GET_DATA(qd); diff --git a/py/runtime.c b/py/runtime.c index 48e815f0fa..6eda77ee9c 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -55,7 +55,6 @@ const mp_obj_module_t mp_module___main__ = { .base = { &mp_type_module }, - .name = MP_QSTR___main__, .globals = (mp_obj_dict_t*)&MP_STATE_VM(dict_main), }; @@ -139,8 +138,7 @@ mp_obj_t mp_load_global(qstr qst) { elem = mp_map_lookup((mp_map_t*)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, - "name not defined")); + mp_raise_msg(&mp_type_NameError, "name not defined"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%q' is not defined", qst)); @@ -231,8 +229,7 @@ mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "unsupported type for operator")); + mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported type for %q: '%s'", @@ -324,7 +321,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); @@ -339,7 +336,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } else { // standard precision is enough for right-shift if (rhs_val >= (mp_int_t)BITS_PER_WORD) { @@ -415,7 +412,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { lhs = mp_obj_new_float(lhs_val); goto generic_binary_op; #else - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); + mp_raise_msg(&mp_type_ValueError, "negative power with no float support"); #endif } else { mp_int_t ans = 1; @@ -516,8 +513,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not iterable")); + mp_raise_msg(&mp_type_TypeError, "object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(rhs))); @@ -539,8 +535,7 @@ generic_binary_op: unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "unsupported type for operator")); + mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported types for %q: '%s', '%s'", @@ -548,7 +543,7 @@ unsupported_op: } zero_division: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mp_obj_t mp_call_function_0(mp_obj_t fun) { @@ -582,8 +577,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args, mp_uint_t n_kw } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not callable")); + mp_raise_msg(&mp_type_TypeError, "object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); @@ -814,16 +808,14 @@ void mp_unpack_sequence(mp_obj_t seq_in, mp_uint_t num, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } too_long: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", (int)num)); @@ -889,8 +881,7 @@ void mp_unpack_ex(mp_obj_t seq_in, mp_uint_t num_in, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); @@ -929,8 +920,7 @@ STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); if (arg0_type != self->type) { if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "argument has wrong type")); + mp_raise_msg(&mp_type_TypeError, "argument has wrong type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); @@ -1046,8 +1036,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // no attribute/method called attr if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, - "no such attribute")); + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { @@ -1075,8 +1064,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, - "no such attribute")); + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", @@ -1106,8 +1094,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in) { // object not iterable if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not iterable")); + mp_raise_msg(&mp_type_TypeError, "object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); @@ -1129,8 +1116,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { return mp_call_method_n_kw(0, 0, dest); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not an iterator")); + mp_raise_msg(&mp_type_TypeError, "object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1166,8 +1152,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not an iterator")); + mp_raise_msg(&mp_type_TypeError, "object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1385,8 +1370,7 @@ void *m_malloc_fail(size_t num_bytes) { // dummy #if MICROPY_ENABLE_GC } else if (gc_is_locked()) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, - "memory allocation failed, heap is locked")); + mp_raise_msg(&mp_type_MemoryError, "memory allocation failed, heap is locked"); #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, @@ -1406,6 +1390,10 @@ NORETURN void mp_raise_TypeError(const char *msg) { mp_raise_msg(&mp_type_TypeError, msg); } +NORETURN void mp_raise_OSError(int errno_) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_))); +} + NORETURN void mp_not_implemented(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } diff --git a/py/runtime.h b/py/runtime.h index 06e68924b2..80488098ae 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -52,8 +52,8 @@ typedef union _mp_arg_val_t { } mp_arg_val_t; typedef struct _mp_arg_t { - qstr qst; - mp_uint_t flags; + uint16_t qst; + uint16_t flags; mp_arg_val_t defval; } mp_arg_t; @@ -137,6 +137,7 @@ NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); //NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); +NORETURN void mp_raise_OSError(int errno_); NORETURN void mp_not_implemented(const char *msg); // Raise NotImplementedError with given message NORETURN void mp_exc_recursion_depth(void); diff --git a/py/scope.c b/py/scope.c index e408251733..8143e655c9 100644 --- a/py/scope.c +++ b/py/scope.c @@ -30,36 +30,27 @@ #if MICROPY_ENABLE_COMPILER +// these low numbered qstrs should fit in 8 bits +STATIC const uint8_t scope_simple_name_table[] = { + [SCOPE_MODULE] = MP_QSTR__lt_module_gt_, + [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_, + [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_, + [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_, + [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_, + [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_, +}; + scope_t *scope_new(scope_kind_t kind, const byte *pn, qstr source_file, mp_uint_t emit_options) { scope_t *scope = m_new0(scope_t, 1); scope->kind = kind; scope->pn = pn; scope->source_file = source_file; - switch (kind) { - case SCOPE_MODULE: - scope->simple_name = MP_QSTR__lt_module_gt_; - break; - case SCOPE_FUNCTION: - case SCOPE_CLASS: - pt_extract_id(pn, &scope->simple_name); // function name - break; - case SCOPE_LAMBDA: - scope->simple_name = MP_QSTR__lt_lambda_gt_; - break; - case SCOPE_LIST_COMP: - scope->simple_name = MP_QSTR__lt_listcomp_gt_; - break; - case SCOPE_DICT_COMP: - scope->simple_name = MP_QSTR__lt_dictcomp_gt_; - break; - case SCOPE_SET_COMP: - scope->simple_name = MP_QSTR__lt_setcomp_gt_; - break; - case SCOPE_GEN_EXPR: - scope->simple_name = MP_QSTR__lt_genexpr_gt_; - break; - default: - assert(0); + if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) { + qstr id; + pt_extract_id(pn, &id); // function name + scope->simple_name = id; + } else { + scope->simple_name = scope_simple_name_table[kind]; } scope->emit_options = emit_options; scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT; @@ -115,22 +106,10 @@ id_info_t *scope_find_global(scope_t *scope, qstr qst) { return scope_find(scope, qst); } -id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qst) { - if (scope->parent == NULL) { - return NULL; - } - for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) { - id_info_t *id = scope_find(s, qst); - if (id != NULL) { - return id; - } - } - return NULL; -} - -void scope_close_over_in_parents(scope_t *scope, qstr qst) { +STATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) { assert(scope->parent != NULL); // we should have at least 1 parent - for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) { + for (scope_t *s = scope->parent;; s = s->parent) { + assert(s->parent != NULL); // we should not get to the outer scope bool added; id_info_t *id = scope_find_or_add_id(s, qst, &added); if (added) { @@ -138,16 +117,34 @@ void scope_close_over_in_parents(scope_t *scope, qstr qst) { id->kind = ID_INFO_KIND_FREE; } else { // variable is declared in this scope, so finish - switch (id->kind) { - case ID_INFO_KIND_LOCAL: id->kind = ID_INFO_KIND_CELL; break; // variable local to this scope, close it over - case ID_INFO_KIND_FREE: break; // variable already closed over in a parent scope - case ID_INFO_KIND_CELL: break; // variable already closed over in this scope - default: assert(0); // TODO + if (id->kind == ID_INFO_KIND_LOCAL) { + // variable local to this scope, close it over + id->kind = ID_INFO_KIND_CELL; + } else { + // ID_INFO_KIND_FREE: variable already closed over in a parent scope + // ID_INFO_KIND_CELL: variable already closed over in this scope + assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL); } return; } } - assert(0); // we should have found the variable in one of the parents +} + +void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst) { + if (scope->parent != NULL) { + for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) { + id_info_t *id2 = scope_find(s, qst); + if (id2 != NULL) { + if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) { + id->kind = ID_INFO_KIND_FREE; + scope_close_over_in_parents(scope, qst); + return; + } + break; + } + } + } + id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; } #endif // MICROPY_ENABLE_COMPILER diff --git a/py/scope.h b/py/scope.h index e210a5a9cf..012d906475 100644 --- a/py/scope.h +++ b/py/scope.h @@ -52,14 +52,26 @@ typedef struct _id_info_t { qstr qst; } id_info_t; +#define SCOPE_IS_FUNC_LIKE(s) ((s) >= SCOPE_LAMBDA) + // scope is a "block" in Python parlance -typedef enum { SCOPE_MODULE, SCOPE_FUNCTION, SCOPE_LAMBDA, SCOPE_LIST_COMP, SCOPE_DICT_COMP, SCOPE_SET_COMP, SCOPE_GEN_EXPR, SCOPE_CLASS } scope_kind_t; +typedef enum { + SCOPE_MODULE, + SCOPE_CLASS, + SCOPE_LAMBDA, + SCOPE_LIST_COMP, + SCOPE_DICT_COMP, + SCOPE_SET_COMP, + SCOPE_GEN_EXPR, + SCOPE_FUNCTION, +} scope_kind_t; + typedef struct _scope_t { scope_kind_t kind; struct _scope_t *parent; const byte *pn; // points to the node after the scope index node - qstr source_file; - qstr simple_name; + uint16_t source_file; // a qstr + uint16_t simple_name; // a qstr mp_raw_code_t *raw_code; uint8_t scope_flags; // see runtime0.h uint8_t emit_options; // see compile.h @@ -79,7 +91,6 @@ void scope_free(scope_t *scope); id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added); id_info_t *scope_find(scope_t *scope, qstr qstr); id_info_t *scope_find_global(scope_t *scope, qstr qstr); -id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr); -void scope_close_over_in_parents(scope_t *scope, qstr qstr); +void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst); #endif // __MICROPY_INCLUDED_PY_SCOPE_H__ diff --git a/py/sequence.c b/py/sequence.c index 239f1b2cc5..0acdd25be0 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -235,7 +235,7 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence")); + mp_raise_msg(&mp_type_ValueError, "object not in sequence"); } mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value) { diff --git a/py/showbc.c b/py/showbc.c index dd5959f4a9..684d9af0c0 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -32,6 +32,9 @@ #if MICROPY_DEBUG_PRINTERS +// redirect all printfs in this file to the platform print stream +#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) + #define DECODE_UINT { \ unum = 0; \ do { \ @@ -96,6 +99,7 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m #if MICROPY_PERSISTENT_CODE qstr block_name = code_info[0] | (code_info[1] << 8); qstr source_file = code_info[2] | (code_info[3] << 8); + code_info += 4; #else qstr block_name = mp_decode_uint(&code_info); qstr source_file = mp_decode_uint(&code_info); @@ -409,11 +413,6 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("BUILD_LIST " UINT_FMT, unum); break; - case MP_BC_LIST_APPEND: - DECODE_UINT; - printf("LIST_APPEND " UINT_FMT, unum); - break; - case MP_BC_BUILD_MAP: DECODE_UINT; printf("BUILD_MAP " UINT_FMT, unum); @@ -423,21 +422,11 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("STORE_MAP"); break; - case MP_BC_MAP_ADD: - DECODE_UINT; - printf("MAP_ADD " UINT_FMT, unum); - break; - case MP_BC_BUILD_SET: DECODE_UINT; printf("BUILD_SET " UINT_FMT, unum); break; - case MP_BC_SET_ADD: - DECODE_UINT; - printf("SET_ADD " UINT_FMT, unum); - break; - #if MICROPY_PY_BUILTINS_SLICE case MP_BC_BUILD_SLICE: DECODE_UINT; @@ -445,6 +434,11 @@ const byte *mp_bytecode_print_str(const byte *ip) { break; #endif + case MP_BC_STORE_COMP: + DECODE_UINT; + printf("STORE_COMP " UINT_FMT, unum); + break; + case MP_BC_UNPACK_SEQUENCE: DECODE_UINT; printf("UNPACK_SEQUENCE " UINT_FMT, unum); diff --git a/py/stream.c b/py/stream.c index eef9080b7b..cc8a63ac2e 100644 --- a/py/stream.c +++ b/py/stream.c @@ -101,7 +101,7 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "stream operation not supported")); + mp_raise_msg(&mp_type_OSError, "stream operation not supported"); } return stream_p; } @@ -159,7 +159,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl } break; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } if (out_sz < more_bytes) { @@ -227,7 +227,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl // this as EOF. return mp_const_none; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } else { vstr.len = out_sz; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); @@ -256,7 +256,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla // no single byte could be readily written to it." return mp_const_none; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -315,7 +315,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { if (mp_is_nonblocking_error(error)) { return mp_const_none; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -343,7 +343,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } break; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } if (out_sz == 0) { break; @@ -355,10 +355,6 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } else { p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE); current_read = DEFAULT_BUFFER_SIZE; - if (p == NULL) { - // TODO - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); - } } } @@ -406,7 +402,7 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) goto done; } } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } if (out_sz == 0) { done: @@ -461,7 +457,7 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { int error; mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); if (res == MP_STREAM_ERROR) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } // TODO: Could be uint64 @@ -482,7 +478,7 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) { int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } return mp_const_none; } @@ -504,7 +500,7 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); + mp_raise_OSError(error); } return mp_obj_new_int(res); @@ -587,6 +587,8 @@ dispatch_loop: // and __exit__ method (with self) underneath it. Bytecode calls __exit__, // and "deletes" it off stack, shifting "exception control block" // to its place. + // The bytecode emitter ensures that there is enough space on the Python + // value stack to hold the __exit__ method plus an additional 4 entries. if (TOP() == mp_const_none) { // stack: (..., __exit__, ctx_mgr, None) sp[1] = mp_const_none; @@ -620,31 +622,26 @@ dispatch_loop: } sp -= 2; // we removed (__exit__, ctx_mgr) } else { - assert(mp_obj_is_exception_type(TOP())); - // stack: (..., __exit__, ctx_mgr, traceback, exc_val, exc_type) - // Need to pass (sp[0], sp[-1], sp[-2]) as arguments so must reverse the - // order of these on the value stack (don't want to create a temporary - // array because it increases stack footprint of the VM). - mp_obj_t obj = sp[-2]; - sp[-2] = sp[0]; - sp[0] = obj; - mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp - 4); + assert(mp_obj_is_exception_instance(TOP())); + // stack: (..., __exit__, ctx_mgr, exc_instance) + // Need to pass (exc_type, exc_instance, None) as arguments to __exit__. + sp[1] = sp[0]; + sp[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(sp[0])); + sp[2] = mp_const_none; + sp -= 2; + mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp); if (mp_obj_is_true(ret_value)) { // We need to silence/swallow the exception. This is done // by popping the exception and the __exit__ handler and // replacing it with None, which signals END_FINALLY to just // execute the finally handler normally. - sp -= 4; SET_TOP(mp_const_none); assert(exc_sp >= exc_stack); POP_EXC_BLOCK(); } else { // We need to re-raise the exception. We pop __exit__ handler - // and copy the 3 exception values down (remembering that they - // are reversed due to above code). - sp[-4] = sp[0]; - sp[-3] = sp[-1]; - sp -= 2; + // by copying the exception instance down to the new top-of-stack. + sp[0] = sp[3]; } } DISPATCH(); @@ -698,18 +695,12 @@ unwind_jump:; ENTRY(MP_BC_END_FINALLY): MARK_EXC_IP_SELECTIVE(); - // not fully implemented - // if TOS is an exception, reraises the exception (3 values on TOS) // if TOS is None, just pops it and continues - // if TOS is an integer, does something else - // else error - if (mp_obj_is_exception_type(TOP())) { - RAISE(sp[-1]); - } + // if TOS is an integer, finishes coroutine and returns control to caller + // if TOS is an exception, reraises the exception if (TOP() == mp_const_none) { sp--; - } else { - assert(MP_OBJ_IS_SMALL_INT(TOP())); + } else if (MP_OBJ_IS_SMALL_INT(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); @@ -719,6 +710,9 @@ unwind_jump:; assert(reason == UNWIND_JUMP); goto unwind_jump; } + } else { + assert(mp_obj_is_exception_instance(TOP())); + RAISE(TOP()); } DISPATCH(); @@ -751,14 +745,9 @@ unwind_jump:; // matched against: SETUP_EXCEPT ENTRY(MP_BC_POP_EXCEPT): - // TODO need to work out how blocks work etc - // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate assert(exc_sp >= exc_stack); assert(currently_in_except_block); - //sp = (mp_obj_t*)(*exc_sp--); - //exc_sp--; // discard ip POP_EXC_BLOCK(); - //sp -= 3; // pop 3 exception values DISPATCH(); ENTRY(MP_BC_BUILD_TUPLE): { @@ -777,15 +766,6 @@ unwind_jump:; DISPATCH(); } - ENTRY(MP_BC_LIST_APPEND): { - MARK_EXC_IP_SELECTIVE(); - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[unum] is a list - mp_obj_list_append(sp[-unum], sp[0]); - sp--; - DISPATCH(); - } - ENTRY(MP_BC_BUILD_MAP): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; @@ -799,15 +779,6 @@ unwind_jump:; mp_obj_dict_store(sp[0], sp[2], sp[1]); DISPATCH(); - ENTRY(MP_BC_MAP_ADD): { - MARK_EXC_IP_SELECTIVE(); - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[-unum - 1] is a map - mp_obj_dict_store(sp[-unum - 1], sp[0], sp[-1]); - sp -= 2; - DISPATCH(); - } - #if MICROPY_PY_BUILTINS_SET ENTRY(MP_BC_BUILD_SET): { MARK_EXC_IP_SELECTIVE(); @@ -816,15 +787,6 @@ unwind_jump:; SET_TOP(mp_obj_new_set(unum, sp)); DISPATCH(); } - - ENTRY(MP_BC_SET_ADD): { - MARK_EXC_IP_SELECTIVE(); - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[-unum] is a set - mp_obj_set_store(sp[-unum], sp[0]); - sp--; - DISPATCH(); - } #endif #if MICROPY_PY_BUILTINS_SLICE @@ -845,6 +807,25 @@ unwind_jump:; } #endif + ENTRY(MP_BC_STORE_COMP): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + mp_obj_t obj = sp[-(unum >> 2)]; + if ((unum & 3) == 0) { + mp_obj_list_append(obj, sp[0]); + sp--; + } else if (!MICROPY_PY_BUILTINS_SET || (unum & 3) == 1) { + mp_obj_dict_store(obj, sp[0], sp[-1]); + sp -= 2; + #if MICROPY_PY_BUILTINS_SET + } else { + mp_obj_set_store(obj, sp[0]); + sp--; + #endif + } + DISPATCH(); + } + ENTRY(MP_BC_UNPACK_SEQUENCE): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; @@ -1367,10 +1348,8 @@ unwind_loop: mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); // save this exception in the stack so it can be used in a reraise, if needed exc_sp->prev_exc = nlr.ret_val; - // push(traceback, exc-val, exc-type) - PUSH(mp_const_none); + // push exception object so it can be handled by bytecode PUSH(MP_OBJ_FROM_PTR(nlr.ret_val)); - PUSH(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type)); code_state->sp = sp; #if MICROPY_STACKLESS diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 9df1e40a32..dd30dd7a54 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -78,17 +78,15 @@ static const void *const entry_table[256] = { [MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT, [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE, [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST, - [MP_BC_LIST_APPEND] = &&entry_MP_BC_LIST_APPEND, [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP, [MP_BC_STORE_MAP] = &&entry_MP_BC_STORE_MAP, - [MP_BC_MAP_ADD] = &&entry_MP_BC_MAP_ADD, #if MICROPY_PY_BUILTINS_SET [MP_BC_BUILD_SET] = &&entry_MP_BC_BUILD_SET, - [MP_BC_SET_ADD] = &&entry_MP_BC_SET_ADD, #endif #if MICROPY_PY_BUILTINS_SLICE [MP_BC_BUILD_SLICE] = &&entry_MP_BC_BUILD_SLICE, #endif + [MP_BC_STORE_COMP] = &&entry_MP_BC_STORE_COMP, [MP_BC_UNPACK_SEQUENCE] = &&entry_MP_BC_UNPACK_SEQUENCE, [MP_BC_UNPACK_EX] = &&entry_MP_BC_UNPACK_EX, [MP_BC_MAKE_FUNCTION] = &&entry_MP_BC_MAKE_FUNCTION, @@ -44,11 +44,6 @@ void vstr_init(vstr_t *vstr, size_t alloc) { vstr->alloc = alloc; vstr->len = 0; vstr->buf = m_new(char, vstr->alloc); - if (vstr->buf == NULL) { - vstr->had_error = true; - return; - } - vstr->had_error = false; vstr->fixed_buf = false; } @@ -63,7 +58,6 @@ void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf) { vstr->alloc = alloc; vstr->len = 0; vstr->buf = buf; - vstr->had_error = false; vstr->fixed_buf = true; } @@ -80,20 +74,8 @@ void vstr_clear(vstr_t *vstr) { vstr->buf = NULL; } -vstr_t *vstr_new(void) { +vstr_t *vstr_new(size_t alloc) { vstr_t *vstr = m_new_obj(vstr_t); - if (vstr == NULL) { - return NULL; - } - vstr_init(vstr, 16); - return vstr; -} - -vstr_t *vstr_new_size(size_t alloc) { - vstr_t *vstr = m_new_obj(vstr_t); - if (vstr == NULL) { - return NULL; - } vstr_init(vstr, alloc); return vstr; } @@ -107,39 +89,12 @@ void vstr_free(vstr_t *vstr) { } } -void vstr_reset(vstr_t *vstr) { - vstr->len = 0; - vstr->had_error = false; -} - -bool vstr_had_error(vstr_t *vstr) { - return vstr->had_error; -} - -char *vstr_str(vstr_t *vstr) { - if (vstr->had_error) { - return NULL; - } - return vstr->buf; -} - -size_t vstr_len(vstr_t *vstr) { - if (vstr->had_error) { - return 0; - } - return vstr->len; -} - // Extend vstr strictly by requested size, return pointer to newly added chunk. char *vstr_extend(vstr_t *vstr, size_t size) { if (vstr->fixed_buf) { return NULL; } char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size); - if (new_buf == NULL) { - vstr->had_error = true; - return NULL; - } char *p = new_buf + vstr->alloc; vstr->alloc += size; vstr->buf = new_buf; @@ -153,10 +108,6 @@ STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { } 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; - return false; - } vstr->alloc = new_alloc; vstr->buf = new_buf; } @@ -164,14 +115,11 @@ STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { } void vstr_hint_size(vstr_t *vstr, size_t size) { - // it's not an error if we fail to allocate for the size hint - bool er = vstr->had_error; vstr_ensure_extra(vstr, size); - vstr->had_error = er; } char *vstr_add_len(vstr_t *vstr, size_t len) { - if (vstr->had_error || !vstr_ensure_extra(vstr, len)) { + if (!vstr_ensure_extra(vstr, len)) { return NULL; } char *buf = vstr->buf + vstr->len; @@ -181,9 +129,6 @@ 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) { - return NULL; - } // If there's no more room, add single byte if (vstr->alloc == vstr->len) { if (vstr_extend(vstr, 1) == NULL) { @@ -248,7 +193,7 @@ void vstr_add_str(vstr_t *vstr, const char *str) { } void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { - if (vstr->had_error || !vstr_ensure_extra(vstr, len)) { + if (!vstr_ensure_extra(vstr, len)) { // if buf is fixed, we got here because there isn't enough room left // so just try to copy as much as we can, with room for a possible null byte if (vstr->fixed_buf && vstr->len < vstr->alloc) { @@ -263,9 +208,6 @@ copy: } char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { - if (vstr->had_error) { - return NULL; - } size_t l = vstr->len; if (byte_pos > l) { byte_pos = l; @@ -303,9 +245,6 @@ void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) { } void vstr_cut_tail_bytes(vstr_t *vstr, size_t len) { - if (vstr->had_error) { - return; - } if (len > vstr->len) { vstr->len = 0; } else { @@ -314,7 +253,7 @@ void vstr_cut_tail_bytes(vstr_t *vstr, size_t len) { } void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut) { - if (vstr->had_error || byte_pos >= vstr->len) { + if (byte_pos >= vstr->len) { return; } else if (byte_pos + bytes_to_cut >= vstr->len) { vstr->len = byte_pos; |