mirror of
https://github.com/micropython/micropython.git
synced 2025-12-31 01:00:14 +01:00
Compare commits
342 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110ba35980 | ||
|
|
1ac6faa732 | ||
|
|
516b09efc3 | ||
|
|
b796e3d848 | ||
|
|
16ee30c6fa | ||
|
|
fe3d16e8c2 | ||
|
|
a97e091d4e | ||
|
|
a75b02ea9b | ||
|
|
ad4c014d46 | ||
|
|
b7f7c655ed | ||
|
|
f3c3010ffc | ||
|
|
b427d6ae86 | ||
|
|
f05b87bd63 | ||
|
|
3b72da674e | ||
|
|
6cf8dd4f51 | ||
|
|
e00fb08f99 | ||
|
|
f4ce26de5c | ||
|
|
db63660c19 | ||
|
|
3bb7efc943 | ||
|
|
cd021bfe56 | ||
|
|
779794a680 | ||
|
|
fa1a9bc9fd | ||
|
|
994bb4a839 | ||
|
|
34e43c7ee9 | ||
|
|
3475b04101 | ||
|
|
29c92a407c | ||
|
|
2bf044442e | ||
|
|
8c0add4eee | ||
|
|
e5cbb70328 | ||
|
|
9480138f0c | ||
|
|
7310fd469a | ||
|
|
1d8a06406a | ||
|
|
2c4e67e32d | ||
|
|
3d945559d4 | ||
|
|
c668d51b08 | ||
|
|
8ba832456e | ||
|
|
6678595e7e | ||
|
|
3c658a4e75 | ||
|
|
25fc41dd31 | ||
|
|
4f9ebade60 | ||
|
|
72b115cbaa | ||
|
|
26a0d4f4f1 | ||
|
|
69b7dae362 | ||
|
|
d5e7f6e37e | ||
|
|
13ec400f28 | ||
|
|
7fe2191c9b | ||
|
|
86de21b810 | ||
|
|
339bdccc58 | ||
|
|
3688414d9d | ||
|
|
8f81b5cb4b | ||
|
|
b63be37be1 | ||
|
|
b0accc8571 | ||
|
|
d779b9642f | ||
|
|
244476e3e6 | ||
|
|
c84aa41990 | ||
|
|
f0c3a7e781 | ||
|
|
6009309c33 | ||
|
|
e6c0dff967 | ||
|
|
a5190a7dac | ||
|
|
2ac4af6946 | ||
|
|
6be0b0a8ec | ||
|
|
bf133f7737 | ||
|
|
2c781eabbd | ||
|
|
9b7a8ee8f1 | ||
|
|
8cce8b7c4c | ||
|
|
9d02780eaf | ||
|
|
1ddd844815 | ||
|
|
5073d3da07 | ||
|
|
8882c20b8f | ||
|
|
510296f25a | ||
|
|
75ec22bf11 | ||
|
|
105e32f1a5 | ||
|
|
f20375eedd | ||
|
|
bb91f1195a | ||
|
|
4c03b3a899 | ||
|
|
69c5fe1df6 | ||
|
|
2eb1f604ee | ||
|
|
7703d71938 | ||
|
|
9749b2fb0d | ||
|
|
2eeeafcba5 | ||
|
|
6e6bcccdc1 | ||
|
|
101d87da6a | ||
|
|
0c5498540b | ||
|
|
ecca53bd34 | ||
|
|
2831a8f800 | ||
|
|
4ef26c14b1 | ||
|
|
30dd23aa7f | ||
|
|
0c64c634ca | ||
|
|
c4ee39dd63 | ||
|
|
5f930337bc | ||
|
|
7133d91773 | ||
|
|
5f47ebbf82 | ||
|
|
2605df3346 | ||
|
|
04019e365f | ||
|
|
590b2abdfc | ||
|
|
ea439e59d9 | ||
|
|
ef7a066c9c | ||
|
|
4162271181 | ||
|
|
b92e7533d3 | ||
|
|
284efa89ae | ||
|
|
4b67463be1 | ||
|
|
5b7c0c437b | ||
|
|
196773505a | ||
|
|
a1d3ee376c | ||
|
|
6f418fc1b0 | ||
|
|
5d9b816449 | ||
|
|
3ef911345c | ||
|
|
8a11d693cf | ||
|
|
2fe2a05f9f | ||
|
|
95ea4f0c95 | ||
|
|
7cc20e7e99 | ||
|
|
56da07dcfa | ||
|
|
dd07023cb7 | ||
|
|
6c70511835 | ||
|
|
0538a203e5 | ||
|
|
2e3e8b2f69 | ||
|
|
ccacdf44b6 | ||
|
|
8dbbbbc793 | ||
|
|
aa6228eaf5 | ||
|
|
ecb5792f88 | ||
|
|
8362bffb2e | ||
|
|
ce23f67d9e | ||
|
|
e40c72210f | ||
|
|
2e41646eb7 | ||
|
|
87bbb388db | ||
|
|
71bed1a9a7 | ||
|
|
8464be15ed | ||
|
|
f8f963a14a | ||
|
|
65dd7bc13d | ||
|
|
5aac6aa445 | ||
|
|
4747becc64 | ||
|
|
8cc2018d47 | ||
|
|
c9aa58e638 | ||
|
|
bb4c6f35c6 | ||
|
|
fa1ecda3fd | ||
|
|
3c4db9f91c | ||
|
|
5f27a7e811 | ||
|
|
94fbe9711a | ||
|
|
07133415d2 | ||
|
|
d0f5e61ab5 | ||
|
|
645582fe14 | ||
|
|
adf0f2ae1a | ||
|
|
5b7fd20fea | ||
|
|
05c255f039 | ||
|
|
ffe911d228 | ||
|
|
1bbdd4ed2a | ||
|
|
4ecb700fe3 | ||
|
|
e1b1abc1e8 | ||
|
|
de993f4573 | ||
|
|
7cfae9693b | ||
|
|
3e0bce3587 | ||
|
|
7a03b5f56a | ||
|
|
86f0b31bcf | ||
|
|
1d8816c36b | ||
|
|
a2e7a1315d | ||
|
|
512465bc66 | ||
|
|
721d6240c9 | ||
|
|
4038f513ea | ||
|
|
951ed9d02f | ||
|
|
1163cb9cb5 | ||
|
|
cb66f41ebc | ||
|
|
04c9fec7d1 | ||
|
|
2c0701101b | ||
|
|
1694bc733d | ||
|
|
02bc882c3d | ||
|
|
0f4ee2e44a | ||
|
|
5467186b0e | ||
|
|
e3737b858a | ||
|
|
a4022c92f0 | ||
|
|
a50494ab68 | ||
|
|
db56ad2915 | ||
|
|
73ab8cc21d | ||
|
|
ef204733d6 | ||
|
|
0429d35f37 | ||
|
|
04f5ae1d1c | ||
|
|
4d9dd26818 | ||
|
|
dce8876dbe | ||
|
|
ac736f15c9 | ||
|
|
122c9db3db | ||
|
|
a1760a56ff | ||
|
|
b82f34edde | ||
|
|
2cf381081a | ||
|
|
564e46452d | ||
|
|
58c9586c34 | ||
|
|
847a6b30b1 | ||
|
|
e687fdbcbc | ||
|
|
2097c8b1e1 | ||
|
|
8215847b4d | ||
|
|
42b6419056 | ||
|
|
594699bc88 | ||
|
|
90ba80dc36 | ||
|
|
5fa5ca40e6 | ||
|
|
539681fffd | ||
|
|
0182385ab0 | ||
|
|
4e0eeebdc2 | ||
|
|
381618269a | ||
|
|
54eb4e723e | ||
|
|
40f3c02682 | ||
|
|
065aba5875 | ||
|
|
e4e55047b3 | ||
|
|
5e6419cb11 | ||
|
|
e70b5dbe58 | ||
|
|
92a47b4dae | ||
|
|
9cd96cf25d | ||
|
|
f83debc716 | ||
|
|
7a37f647a5 | ||
|
|
5fc580475f | ||
|
|
f0b29729aa | ||
|
|
f065344d3b | ||
|
|
aa47f3968b | ||
|
|
2fe841d2fa | ||
|
|
caa7334141 | ||
|
|
e95b6b5e07 | ||
|
|
0d81c133b3 | ||
|
|
5d44e6a92c | ||
|
|
4039a26679 | ||
|
|
b601d9574a | ||
|
|
5813efd634 | ||
|
|
bb35f425f9 | ||
|
|
c10a4405cd | ||
|
|
a23475979b | ||
|
|
ec6fa8732b | ||
|
|
8139494e54 | ||
|
|
9e215fa4c2 | ||
|
|
a62da515af | ||
|
|
5478ed18ea | ||
|
|
b1b840554d | ||
|
|
635b60e299 | ||
|
|
8546ce1e28 | ||
|
|
41736f8201 | ||
|
|
e04a44e2f6 | ||
|
|
b3a50f0f3e | ||
|
|
8993fb6cf0 | ||
|
|
7e4ec3bf4f | ||
|
|
81df1e6c98 | ||
|
|
cb78f862cb | ||
|
|
0a1ea40273 | ||
|
|
8a96ebea75 | ||
|
|
64c58403ef | ||
|
|
a75e382a9b | ||
|
|
3c8ce38d20 | ||
|
|
3659af97c5 | ||
|
|
ed07d035d5 | ||
|
|
f5f6c3b792 | ||
|
|
ce81312d8a | ||
|
|
63143c94ce | ||
|
|
ea2c936c7e | ||
|
|
26fda6dc8e | ||
|
|
00c904b47a | ||
|
|
1044c3dfe6 | ||
|
|
b1949e4c09 | ||
|
|
5048df0b7c | ||
|
|
46d31e9ca9 | ||
|
|
ded0fc77f7 | ||
|
|
17994d1bd3 | ||
|
|
79b7fe2ee5 | ||
|
|
cdc020da4b | ||
|
|
e7f2b4c875 | ||
|
|
86d3898e70 | ||
|
|
d215ee1dc1 | ||
|
|
9731912ccb | ||
|
|
165eb69b86 | ||
|
|
42a52516fe | ||
|
|
2ba2299d28 | ||
|
|
1e3781bc35 | ||
|
|
9a1a4beb56 | ||
|
|
64b468d873 | ||
|
|
83865347db | ||
|
|
c88987c1af | ||
|
|
12bc13eeb8 | ||
|
|
16ac4962ae | ||
|
|
7a8ab5a730 | ||
|
|
23668698cb | ||
|
|
91b576d147 | ||
|
|
f170735b73 | ||
|
|
f3de62e6c2 | ||
|
|
8e01291c18 | ||
|
|
7a2f166949 | ||
|
|
39b6e27944 | ||
|
|
5aa740c3e2 | ||
|
|
e973acde81 | ||
|
|
939c2e7f44 | ||
|
|
3c9b24bebe | ||
|
|
141df2d350 | ||
|
|
780e54cdc3 | ||
|
|
cd590cbfaa | ||
|
|
ff5932a8d8 | ||
|
|
949a49c9da | ||
|
|
69d0a1c540 | ||
|
|
de5ce6d461 | ||
|
|
8abcf666cb | ||
|
|
a96cc824bd | ||
|
|
59c675a64c | ||
|
|
89b38d96c9 | ||
|
|
5c8db48541 | ||
|
|
4c4b9d15ab | ||
|
|
0fc7efb663 | ||
|
|
17a49431d4 | ||
|
|
7cd46a12ae | ||
|
|
7e56e55252 | ||
|
|
eecf3e90c6 | ||
|
|
2099b6897f | ||
|
|
f605172d2b | ||
|
|
3b6f7b95eb | ||
|
|
7efbd325bb | ||
|
|
09e3f8f0d1 | ||
|
|
b6af4c8104 | ||
|
|
74c710187c | ||
|
|
59ced651b5 | ||
|
|
17db096505 | ||
|
|
e53d2197e4 | ||
|
|
f6932d6506 | ||
|
|
bf3366a48b | ||
|
|
fe81eea967 | ||
|
|
b0851e5949 | ||
|
|
c3cabf4e33 | ||
|
|
afc67c6dc5 | ||
|
|
9acb5e4cf0 | ||
|
|
def10cecd1 | ||
|
|
720f55cc4b | ||
|
|
bcb3ab451b | ||
|
|
535b88133c | ||
|
|
bbcea3f62b | ||
|
|
4f1b7fec9f | ||
|
|
2547928148 | ||
|
|
c0711cbefa | ||
|
|
e79c6696c5 | ||
|
|
34ab8dd6dd | ||
|
|
0294661da5 | ||
|
|
812025bd83 | ||
|
|
5f6f47a688 | ||
|
|
00db5c81e1 | ||
|
|
34e7b67d3c | ||
|
|
e3cfc0d33d | ||
|
|
7ddbd1bee7 | ||
|
|
b0bb458810 | ||
|
|
2ec38a17d4 | ||
|
|
e9036c295c | ||
|
|
c037694957 | ||
|
|
63b2237323 | ||
|
|
e22cddbe2a | ||
|
|
f33385f56d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,3 +32,6 @@ tests/*.out
|
||||
# Python cache files
|
||||
######################
|
||||
__pycache__/
|
||||
|
||||
# Customized Makefile overrides
|
||||
GNUmakefile
|
||||
|
||||
@@ -15,9 +15,11 @@ script:
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm
|
||||
- make -C stmhal
|
||||
- make -C stmhal BOARD=STM32F4DISC
|
||||
- make -C teensy
|
||||
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
|
||||
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests)
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff $testbase.exp $testbase.out; done)
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
|
||||
@@ -92,4 +92,4 @@ You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
|
||||
AUR. If the above does not work it may be because you don't have the
|
||||
correct permissions. Try then:
|
||||
|
||||
$ sudo dfu-util -a 0 -D build-PYBV10/firmware.dfu
|
||||
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu
|
||||
|
||||
@@ -13,7 +13,7 @@ INC += -I$(PY_SRC)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
@@ -22,7 +22,7 @@ else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS = --nostdlib -T stm32f405.ld
|
||||
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
|
||||
LIBS =
|
||||
|
||||
SRC_C = \
|
||||
|
||||
@@ -53,7 +53,6 @@ void do_str(const char *src) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
qstr_init();
|
||||
mp_init();
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\n')");
|
||||
mp_deinit();
|
||||
|
||||
@@ -12,10 +12,13 @@
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
@@ -26,20 +29,24 @@
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
|
||||
//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
|
||||
#define UINT_FMT "%lu"
|
||||
#define INT_FMT "%ld"
|
||||
|
||||
typedef int32_t machine_int_t; // must be pointer size
|
||||
typedef uint32_t machine_uint_t; // must be pointer size
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
|
||||
58
examples/pins.py
Normal file
58
examples/pins.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# Print a nice list of pins, their current settings, and available afs.
|
||||
# Requires pins_af.py from stmhal/build-PYBV10/ directory.
|
||||
|
||||
import pyb
|
||||
import pins_af
|
||||
|
||||
def af():
|
||||
max_name_width = 0
|
||||
max_af_width = 0
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
max_name_width = max(max_name_width, len(pin_entry[0]))
|
||||
for af_entry in pin_entry[1:]:
|
||||
max_af_width = max(max_af_width, len(af_entry[1]))
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
pin_name = pin_entry[0]
|
||||
print('%-*s ' % (max_name_width, pin_name), end='')
|
||||
for af_entry in pin_entry[1:]:
|
||||
print('%2d: %-*s ' % (af_entry[0], max_af_width, af_entry[1]), end='')
|
||||
print('')
|
||||
|
||||
def pins():
|
||||
mode_str = { pyb.Pin.IN : 'IN',
|
||||
pyb.Pin.OUT_PP : 'OUT_PP',
|
||||
pyb.Pin.OUT_OD : 'OUT_OD',
|
||||
pyb.Pin.AF_PP : 'AF_PP',
|
||||
pyb.Pin.AF_OD : 'AF_OD',
|
||||
pyb.Pin.ANALOG : 'ANALOG' }
|
||||
pull_str = { pyb.Pin.PULL_NONE : '',
|
||||
pyb.Pin.PULL_UP : 'PULL_UP',
|
||||
pyb.Pin.PULL_DOWN : 'PULL_DOWN' }
|
||||
width = [0, 0, 0, 0]
|
||||
rows = []
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
row = []
|
||||
pin_name = pin_entry[0]
|
||||
pin = pyb.Pin(pin_name)
|
||||
pin_mode = pin.mode()
|
||||
row.append(pin_name)
|
||||
row.append(mode_str[pin_mode])
|
||||
row.append(pull_str[pin.pull()])
|
||||
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
|
||||
pin_af = pin.af()
|
||||
for af_entry in pin_entry[1:]:
|
||||
if pin_af == af_entry[0]:
|
||||
af_str = '%d: %s' % (pin_af, af_entry[1])
|
||||
break
|
||||
else:
|
||||
af_str = '%d' % pin_af
|
||||
else:
|
||||
af_str = ''
|
||||
row.append(af_str)
|
||||
for col in range(len(width)):
|
||||
width[col] = max(width[col], len(row[col]))
|
||||
rows.append(row)
|
||||
for row in rows:
|
||||
for col in range(len(width)):
|
||||
print('%-*s ' % (width[col], row[col]), end='')
|
||||
print('')
|
||||
595
extmod/miniz/tinfl.c
Normal file
595
extmod/miniz/tinfl.c
Normal file
@@ -0,0 +1,595 @@
|
||||
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
|
||||
See "unlicense" statement at the end of this file.
|
||||
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
|
||||
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
|
||||
|
||||
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
|
||||
*/
|
||||
#ifndef TINFL_HEADER_INCLUDED
|
||||
#define TINFL_HEADER_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char mz_uint8;
|
||||
typedef signed short mz_int16;
|
||||
typedef unsigned short mz_uint16;
|
||||
typedef unsigned int mz_uint32;
|
||||
typedef unsigned int mz_uint;
|
||||
typedef unsigned long long mz_uint64;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
|
||||
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
||||
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
|
||||
#define MINIZ_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
||||
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
|
||||
#define MINIZ_HAS_64BIT_REGISTERS 1
|
||||
#endif
|
||||
|
||||
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
|
||||
#ifdef _MSC_VER
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#else
|
||||
#define MZ_MACRO_END while (0)
|
||||
#endif
|
||||
|
||||
// Decompression flags used by tinfl_decompress().
|
||||
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
|
||||
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
|
||||
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
|
||||
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
|
||||
enum
|
||||
{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
|
||||
// On entry:
|
||||
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
|
||||
// On return:
|
||||
// Function returns a pointer to the decompressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must free() the returned block when it's no longer needed.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
|
||||
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
|
||||
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
|
||||
// Max size of LZ dictionary.
|
||||
#define TINFL_LZ_DICT_SIZE 32768
|
||||
|
||||
// Return status.
|
||||
typedef enum
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
} tinfl_status;
|
||||
|
||||
// Initializes the decompressor to its initial state.
|
||||
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
|
||||
#define tinfl_get_adler32(r) (r)->m_check_adler32
|
||||
|
||||
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
|
||||
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
|
||||
|
||||
// Internal/private bits follow.
|
||||
// dpgeorge: TINFL_FAST_LOOKUP_BITS can be adjusted to trade off RAM usage against speed.
|
||||
enum
|
||||
{
|
||||
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TINFL_FAST_LOOKUP_BITS = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
} tinfl_huff_table;
|
||||
|
||||
#if MINIZ_HAS_64BIT_REGISTERS
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#endif
|
||||
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
#else
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
#endif
|
||||
|
||||
struct tinfl_decompressor_tag
|
||||
{
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
};
|
||||
|
||||
#endif // #ifdef TINFL_HEADER_INCLUDED
|
||||
|
||||
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
|
||||
|
||||
#ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
|
||||
#ifdef MINIZ_NO_MALLOC
|
||||
#define MZ_MALLOC(x) NULL
|
||||
#define MZ_FREE(x) x, ((void)0)
|
||||
#define MZ_REALLOC(p, x) NULL
|
||||
#else
|
||||
#define MZ_MALLOC(x) malloc(x)
|
||||
#define MZ_FREE(x) free(x)
|
||||
#define MZ_REALLOC(p, x) realloc(p, x)
|
||||
#endif
|
||||
|
||||
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
|
||||
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
|
||||
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
|
||||
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
|
||||
#else
|
||||
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
|
||||
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
||||
#endif
|
||||
|
||||
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
|
||||
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
|
||||
|
||||
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
|
||||
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
|
||||
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
|
||||
#define TINFL_CR_FINISH }
|
||||
|
||||
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
|
||||
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
|
||||
#define TINFL_GET_BYTE(state_index, c) do { \
|
||||
if (pIn_buf_cur >= pIn_buf_end) { \
|
||||
for ( ; ; ) { \
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
|
||||
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
|
||||
if (pIn_buf_cur < pIn_buf_end) { \
|
||||
c = *pIn_buf_cur++; \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
c = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else c = *pIn_buf_cur++; } MZ_MACRO_END
|
||||
|
||||
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
|
||||
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
|
||||
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
|
||||
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
|
||||
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
|
||||
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
|
||||
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
|
||||
do { \
|
||||
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
|
||||
if (temp >= 0) { \
|
||||
code_len = temp >> 9; \
|
||||
if ((code_len) && (num_bits >= code_len)) \
|
||||
break; \
|
||||
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; \
|
||||
do { \
|
||||
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
|
||||
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
|
||||
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
|
||||
} while (num_bits < 15);
|
||||
|
||||
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
|
||||
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
|
||||
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
|
||||
// The slow path is only executed at the very end of the input buffer.
|
||||
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
|
||||
int temp; mz_uint code_len, c; \
|
||||
if (num_bits < 15) { \
|
||||
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
|
||||
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
|
||||
} else { \
|
||||
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
|
||||
} \
|
||||
} \
|
||||
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
|
||||
code_len = temp >> 9, temp &= 511; \
|
||||
else { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
|
||||
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
|
||||
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
|
||||
{
|
||||
static const mz_uint16 s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
|
||||
static const mz_uint8 s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
|
||||
static const mz_uint16 s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
|
||||
static const mz_uint8 s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
|
||||
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
||||
static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 };
|
||||
|
||||
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
|
||||
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
|
||||
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
|
||||
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
|
||||
|
||||
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
|
||||
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
|
||||
|
||||
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
|
||||
TINFL_CR_BEGIN
|
||||
|
||||
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
|
||||
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
|
||||
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
|
||||
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
|
||||
if (r->m_type == 0)
|
||||
{
|
||||
TINFL_SKIP_BITS(5, num_bits & 7);
|
||||
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
|
||||
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
|
||||
while ((counter) && (num_bits))
|
||||
{
|
||||
TINFL_GET_BITS(51, dist, 8);
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)dist;
|
||||
counter--;
|
||||
}
|
||||
while (counter)
|
||||
{
|
||||
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
while (pIn_buf_cur >= pIn_buf_end)
|
||||
{
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
|
||||
{
|
||||
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
|
||||
}
|
||||
}
|
||||
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
|
||||
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
|
||||
}
|
||||
}
|
||||
else if (r->m_type == 3)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->m_type == 1)
|
||||
{
|
||||
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
|
||||
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
|
||||
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
|
||||
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
|
||||
r->m_table_sizes[2] = 19;
|
||||
}
|
||||
for ( ; (int)r->m_type >= 0; r->m_type--)
|
||||
{
|
||||
int tree_next, tree_cur; tinfl_huff_table *pTable;
|
||||
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
|
||||
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
|
||||
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
|
||||
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
|
||||
if ((65536 != total) && (used_syms > 1))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
|
||||
}
|
||||
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
|
||||
{
|
||||
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
|
||||
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
|
||||
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
|
||||
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
|
||||
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
|
||||
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
|
||||
{
|
||||
tree_cur -= ((rev_code >>= 1) & 1);
|
||||
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
|
||||
}
|
||||
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
|
||||
}
|
||||
if (r->m_type == 2)
|
||||
{
|
||||
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
|
||||
{
|
||||
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
|
||||
if ((dist == 16) && (!counter))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
|
||||
}
|
||||
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
|
||||
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
|
||||
}
|
||||
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
|
||||
}
|
||||
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
|
||||
}
|
||||
}
|
||||
for ( ; ; )
|
||||
{
|
||||
mz_uint8 *pSrc;
|
||||
for ( ; ; )
|
||||
{
|
||||
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
|
||||
{
|
||||
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
|
||||
if (counter >= 256)
|
||||
break;
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sym2; mz_uint code_len;
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
|
||||
#else
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
|
||||
if (counter & 256)
|
||||
break;
|
||||
|
||||
#if !TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
bit_buf >>= code_len; num_bits -= code_len;
|
||||
|
||||
pOut_buf_cur[0] = (mz_uint8)counter;
|
||||
if (sym2 & 256)
|
||||
{
|
||||
pOut_buf_cur++;
|
||||
counter = sym2;
|
||||
break;
|
||||
}
|
||||
pOut_buf_cur[1] = (mz_uint8)sym2;
|
||||
pOut_buf_cur += 2;
|
||||
}
|
||||
}
|
||||
if ((counter &= 511) == 256) break;
|
||||
|
||||
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
|
||||
|
||||
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
|
||||
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
|
||||
|
||||
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
|
||||
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
|
||||
}
|
||||
|
||||
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
|
||||
|
||||
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
|
||||
{
|
||||
while (counter--)
|
||||
{
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
|
||||
else if ((counter >= 9) && (counter <= dist))
|
||||
{
|
||||
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
|
||||
do
|
||||
{
|
||||
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
|
||||
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
|
||||
pOut_buf_cur += 8;
|
||||
} while ((pSrc += 8) < pSrc_end);
|
||||
if ((counter &= 7) < 3)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if (counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
do
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur[2] = pSrc[2];
|
||||
pOut_buf_cur += 3; pSrc += 3;
|
||||
} while ((int)(counter -= 3) > 2);
|
||||
if ((int)counter > 0)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if ((int)counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(r->m_final & 1));
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
|
||||
}
|
||||
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
|
||||
TINFL_CR_FINISH
|
||||
|
||||
common_exit:
|
||||
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
|
||||
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
|
||||
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
|
||||
{
|
||||
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
|
||||
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
|
||||
while (buf_len)
|
||||
{
|
||||
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
|
||||
{
|
||||
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
|
||||
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
|
||||
}
|
||||
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
|
||||
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
|
||||
}
|
||||
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Higher level helper functions.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
|
||||
*pOut_len = 0;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
|
||||
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
src_buf_ofs += src_buf_size;
|
||||
*pOut_len += dst_buf_size;
|
||||
if (status == TINFL_STATUS_DONE) break;
|
||||
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
|
||||
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
|
||||
if (!pNew_buf)
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
|
||||
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
|
||||
}
|
||||
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
|
||||
{
|
||||
int result = 0;
|
||||
tinfl_decompressor decomp;
|
||||
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
|
||||
if (!pDict)
|
||||
return TINFL_STATUS_FAILED;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
|
||||
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
|
||||
in_buf_ofs += in_buf_size;
|
||||
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
|
||||
break;
|
||||
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
|
||||
{
|
||||
result = (status == TINFL_STATUS_DONE);
|
||||
break;
|
||||
}
|
||||
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
|
||||
}
|
||||
MZ_FREE(pDict);
|
||||
*pIn_buf_size = in_buf_ofs;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
634
extmod/moductypes.c
Normal file
634
extmod/moductypes.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "objtuple.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// The module also provides convenience functions to access memory buffers
|
||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
||||
/// \constant UINT8_1 - uint8_t value type
|
||||
|
||||
/// \class struct - C-like structure
|
||||
///
|
||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
||||
/// any methods, only attribute access (for structure fields) and
|
||||
/// indexing (for pointer and array fields).
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// # Define layout of a structure with 2 fields
|
||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
||||
/// # they are logically ORed with field type
|
||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
||||
///
|
||||
/// # Example memory buffer to access (contained in bytes object)
|
||||
/// buf = b"\x64\0\0\0\0x14"
|
||||
///
|
||||
/// # Create structure object referring to address of
|
||||
/// # the data in the buffer above
|
||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
||||
///
|
||||
/// # Access fields
|
||||
/// print(s.a, s.b)
|
||||
/// # Result:
|
||||
/// # 100, 20
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
#define LAYOUT_NATIVE (2)
|
||||
|
||||
#define VAL_TYPE_BITS 4
|
||||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#define OFFSET_BITS 17
|
||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||
#error Invalid encoding field length
|
||||
#endif
|
||||
|
||||
enum {
|
||||
UINT8, INT8, UINT16, INT16,
|
||||
UINT32, INT32, UINT64, INT64,
|
||||
|
||||
BFUINT8, BFINT8, BFUINT16, BFINT16,
|
||||
BFUINT32, BFINT32,
|
||||
|
||||
FLOAT32, FLOAT64,
|
||||
};
|
||||
|
||||
#define AGG_TYPE_BITS 2
|
||||
|
||||
enum {
|
||||
STRUCT, PTR, ARRAY, BITFIELD,
|
||||
};
|
||||
|
||||
// Here we need to set sign bit right
|
||||
#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
|
||||
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1));
|
||||
// Bit 0 is "is_signed"
|
||||
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
|
||||
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type;
|
||||
|
||||
typedef struct _mp_obj_uctypes_struct_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t desc;
|
||||
byte *addr;
|
||||
uint32_t flags;
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
STATIC NORETURN void syntax_error() {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
if (n_args < 2 || n_args > 3) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = type_in;
|
||||
o->desc = args[0];
|
||||
o->addr = (void*)mp_obj_get_int(args[1]);
|
||||
o->flags = LAYOUT_NATIVE;
|
||||
if (n_args == 3) {
|
||||
o->flags = mp_obj_get_int(args[2]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
const char *typen = "unk";
|
||||
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
typen = "STRUCT";
|
||||
} else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
switch (agg_type) {
|
||||
case PTR: typen = "PTR"; break;
|
||||
case ARRAY: typen = "ARRAY"; break;
|
||||
}
|
||||
} else {
|
||||
typen = "ERROR";
|
||||
}
|
||||
print(env, "<struct %s %p>", typen, self->addr);
|
||||
}
|
||||
|
||||
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
|
||||
if (val_type == FLOAT32) {
|
||||
return 4;
|
||||
} else {
|
||||
return GET_SCALAR_SIZE(val_type & 7);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
|
||||
mp_obj_dict_t *d = desc_in;
|
||||
mp_uint_t total_size = 0;
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
for (mp_uint_t i = 0; i < d->map.alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) {
|
||||
mp_obj_t v = d->map.table[i].value;
|
||||
if (MP_OBJ_IS_SMALL_INT(v)) {
|
||||
mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t s = uctypes_struct_scalar_size(val_type);
|
||||
if (s > *max_field_size) {
|
||||
*max_field_size = s;
|
||||
}
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTR: {
|
||||
if (offset + sizeof(void*) > total_size) {
|
||||
total_size = offset + sizeof(void*);
|
||||
}
|
||||
if (sizeof(void*) > *max_field_size) {
|
||||
*max_field_size = sizeof(void*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARRAY: {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
} else {
|
||||
item_s = uctypes_struct_size(t->items[2], max_field_size);
|
||||
}
|
||||
|
||||
mp_uint_t byte_sz = item_s * arr_sz;
|
||||
if (offset + byte_sz > total_size) {
|
||||
total_size = offset + byte_sz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Round size up to alignment of biggest field
|
||||
total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
|
||||
mp_uint_t max_field_size = 0;
|
||||
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
|
||||
mp_obj_uctypes_struct_t *obj = obj_in;
|
||||
obj_in = obj->desc;
|
||||
}
|
||||
mp_uint_t size = uctypes_struct_size(obj_in, &max_field_size);
|
||||
return MP_OBJ_NEW_SMALL_INT(size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_sizeof_obj, uctypes_struct_sizeof);
|
||||
|
||||
STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
|
||||
mp_int_t val = mp_binary_get_int(GET_SCALAR_SIZE(val_type), val_type & 1, big_endian, p);
|
||||
if (val_type == UINT32) {
|
||||
return mp_obj_new_int_from_uint(val);
|
||||
} else {
|
||||
return mp_obj_new_int(val);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC inline void set_unaligned(uint val_type, void *p, int big_endian, mp_obj_t val) {
|
||||
char struct_type = big_endian ? '>' : '<';
|
||||
static const char type2char[8] = "BbHhIiQq";
|
||||
mp_binary_set_val(struct_type, type2char[val_type], val, (byte**)&p);
|
||||
}
|
||||
|
||||
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return *(uint8_t*)p;
|
||||
case UINT16:
|
||||
return *(uint16_t*)p;
|
||||
case UINT32:
|
||||
return *(uint32_t*)p;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
*(uint8_t*)p = (uint8_t)v; return;
|
||||
case UINT16:
|
||||
*(uint16_t*)p = (uint16_t)v; return;
|
||||
case UINT32:
|
||||
*(uint32_t*)p = (uint32_t)v; return;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]);
|
||||
case INT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]);
|
||||
case UINT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]);
|
||||
case INT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]);
|
||||
case UINT32:
|
||||
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
|
||||
case INT32:
|
||||
return mp_obj_new_int(((int32_t*)p)[index]);
|
||||
case UINT64:
|
||||
case INT64:
|
||||
return mp_obj_new_int_from_ll(((int64_t*)p)[index]);
|
||||
case FLOAT32:
|
||||
return mp_obj_new_float(((float*)p)[index]);
|
||||
case FLOAT64:
|
||||
return mp_obj_new_float(((double*)p)[index]);
|
||||
default:
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||
mp_int_t v = mp_obj_get_int(val);
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
((uint8_t*)p)[index] = (uint8_t)v; return;
|
||||
case INT8:
|
||||
((int8_t*)p)[index] = (int8_t)v; return;
|
||||
case UINT16:
|
||||
((uint16_t*)p)[index] = (uint16_t)v; return;
|
||||
case INT16:
|
||||
((int16_t*)p)[index] = (int16_t)v; return;
|
||||
case UINT32:
|
||||
((uint32_t*)p)[index] = (uint32_t)v; return;
|
||||
case INT32:
|
||||
((int32_t*)p)[index] = (int32_t)v; return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
// TODO: Support at least OrderedDict in addition
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: no fields"));
|
||||
}
|
||||
|
||||
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
||||
if (MP_OBJ_IS_SMALL_INT(deref)) {
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
//printf("scalar type=%d offset=%x\n", val_type, offset);
|
||||
|
||||
if (val_type <= INT64) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_aligned(val_type, self->addr + offset, 0);
|
||||
} else {
|
||||
set_aligned(val_type, self->addr + offset, 0, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
} else {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_unaligned(val_type, self->addr + offset, self->flags);
|
||||
} else {
|
||||
set_unaligned(val_type, self->addr + offset, self->flags, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||
} else {
|
||||
val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
|
||||
}
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
val >>= bit_offset;
|
||||
val &= (1 << bit_len) - 1;
|
||||
// TODO: signed
|
||||
assert((val_type & 1) == 0);
|
||||
return mp_obj_new_int(val);
|
||||
} else {
|
||||
mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
|
||||
mp_uint_t mask = (1 << bit_len) - 1;
|
||||
set_val_int &= mask;
|
||||
set_val_int <<= bit_offset;
|
||||
mask <<= bit_offset;
|
||||
val = (val & ~mask) | set_val_int;
|
||||
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
set_aligned_basic(val_type & 6, self->addr + offset, val);
|
||||
} else {
|
||||
mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
|
||||
self->addr + offset, (byte*)&val);
|
||||
}
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
if (set_val != MP_OBJ_NULL) {
|
||||
// Cannot assign to aggregate
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *sub = (mp_obj_tuple_t*)deref;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
//printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub->items[1];
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
case PTR: case ARRAY: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub;
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
//printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
// Should be unreachable once all cases are handled
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
|
||||
*dest = val;
|
||||
}
|
||||
|
||||
STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
|
||||
return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: cannot index"));
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
|
||||
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
|
||||
|
||||
if (agg_type == ARRAY) {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
if (index >= arr_sz) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range"));
|
||||
}
|
||||
|
||||
if (t->len == 2) {
|
||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[2], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[2];
|
||||
o->addr = self->addr + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
} else if (agg_type == PTR) {
|
||||
byte *p = *(void**)self->addr;
|
||||
if (MP_OBJ_IS_SMALL_INT(t->items[1])) {
|
||||
uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
|
||||
return get_aligned(val_type, p, index);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[1], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[1];
|
||||
o->addr = p + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
} else {
|
||||
// store
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
return mp_obj_new_int((mp_int_t)bufinfo.buf);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytes((void*)mp_obj_int_get(ptr), mp_obj_int_get(size));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_struct,
|
||||
.print = uctypes_struct_print,
|
||||
.make_new = uctypes_struct_make_new,
|
||||
.load_attr = uctypes_struct_load_attr,
|
||||
.store_attr = uctypes_struct_store_attr,
|
||||
.subscr = uctypes_struct_subscr,
|
||||
};
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uctypes_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uctypes) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&uctypes_struct_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sizeof), (mp_obj_t)&uctypes_struct_sizeof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_addressof), (mp_obj_t)&uctypes_struct_addressof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes_at), (mp_obj_t)&uctypes_struct_bytes_at_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray_at), (mp_obj_t)&uctypes_struct_bytearray_at_obj },
|
||||
|
||||
/// \moduleref uctypes
|
||||
|
||||
/// \constant NATIVE - Native structure layout - native endianness,
|
||||
/// platform-specific field alignment
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_NATIVE), MP_OBJ_NEW_SMALL_INT(LAYOUT_NATIVE) },
|
||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BIG_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_BIG_ENDIAN) },
|
||||
|
||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_VOID), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \constant UINT32 - uint32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
/// \constant INT32 - int32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
/// \constant UINT64 - uint64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
/// \constant INT64 - int64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_POS), MP_OBJ_NEW_SMALL_INT(17) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_LEN), MP_OBJ_NEW_SMALL_INT(22) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PTR), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ARRAY), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uctypes_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uctypes_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uctypes,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
108
extmod/modzlibd.c
Normal file
108
extmod/modzlibd.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_ZLIBD
|
||||
|
||||
#include "miniz/tinfl.c"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
tinfl_decompressor *decomp = m_new_obj(tinfl_decompressor);
|
||||
tinfl_init(decomp);
|
||||
DEBUG_printf("sizeof(tinfl_decompressor)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
|
||||
|
||||
byte *out = m_new(byte, bufinfo.len);
|
||||
size_t out_len = bufinfo.len;
|
||||
size_t in_buf_ofs = 0, dst_buf_ofs = 0;
|
||||
size_t dst_buf_sz = bufinfo.len;
|
||||
|
||||
while (1) {
|
||||
size_t in_buf_sz = bufinfo.len - in_buf_ofs;
|
||||
DEBUG_printf("tinfl in: in_ofs=%d in_sz=%d dst_ofs=%d, dst_sz=%d\n", in_buf_ofs, in_buf_sz, dst_buf_ofs, dst_buf_sz);
|
||||
tinfl_status st = tinfl_decompress(decomp,
|
||||
bufinfo.buf + in_buf_ofs, &in_buf_sz,
|
||||
out, out + dst_buf_ofs, &dst_buf_sz,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
DEBUG_printf("tinfl out: st=%d, in_sz=%d, out_sz=%d\n", st, in_buf_sz, dst_buf_sz);
|
||||
in_buf_ofs += in_buf_sz;
|
||||
dst_buf_ofs += dst_buf_sz;
|
||||
if (st != TINFL_STATUS_HAS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
out = m_renew(byte, out, out_len, dst_buf_ofs + 256);
|
||||
out_len = dst_buf_ofs + 256;
|
||||
dst_buf_sz = out_len - dst_buf_ofs;
|
||||
}
|
||||
|
||||
m_del_obj(tinfl_decompressor, decomp);
|
||||
return mp_obj_new_bytearray_by_ref(dst_buf_ofs, out);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_zlibd_decompress_obj, 1, 3, mod_zlibd_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_zlibd_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_zlibd) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_zlibd_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_zlibd_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_zlibd_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_zlibd = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_zlibd,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_zlibd_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_ZLIBD
|
||||
327
py/asmarm.c
Normal file
327
py/asmarm.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Fabian Vogt
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmarm.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_ARM
|
||||
|
||||
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
|
||||
|
||||
struct _asm_arm_t {
|
||||
uint pass;
|
||||
uint code_offset;
|
||||
uint code_size;
|
||||
byte *code_base;
|
||||
byte dummy_data[4];
|
||||
|
||||
uint max_num_labels;
|
||||
int *label_offsets;
|
||||
int num_locals;
|
||||
uint push_reglist;
|
||||
uint stack_adjust;
|
||||
};
|
||||
|
||||
asm_arm_t *asm_arm_new(uint max_num_labels) {
|
||||
asm_arm_t *as;
|
||||
|
||||
as = m_new0(asm_arm_t, 1);
|
||||
as->max_num_labels = max_num_labels;
|
||||
as->label_offsets = m_new(int, max_num_labels);
|
||||
|
||||
return as;
|
||||
}
|
||||
|
||||
void asm_arm_free(asm_arm_t *as, bool free_code) {
|
||||
if (free_code) {
|
||||
m_del(byte, as->code_base, as->code_size);
|
||||
}
|
||||
|
||||
m_del_obj(asm_arm_t, as);
|
||||
}
|
||||
|
||||
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_ARM_PASS_COMPUTE) {
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as) {
|
||||
if (as->pass == ASM_ARM_PASS_COMPUTE) {
|
||||
// calculate size of code in bytes
|
||||
as->code_size = as->code_offset;
|
||||
as->code_base = m_new(byte, as->code_size);
|
||||
}
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length
|
||||
STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) {
|
||||
if (as->pass < ASM_ARM_PASS_EMIT) {
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return as->dummy_data;
|
||||
} else {
|
||||
assert(as->code_offset + num_bytes_to_write <= as->code_size);
|
||||
byte *c = as->code_base + as->code_offset;
|
||||
as->code_offset += num_bytes_to_write;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
uint asm_arm_get_code_size(asm_arm_t *as) {
|
||||
return as->code_size;
|
||||
}
|
||||
|
||||
void *asm_arm_get_code(asm_arm_t *as) {
|
||||
return as->code_base;
|
||||
}
|
||||
|
||||
// Insert word into instruction flow
|
||||
STATIC void emit(asm_arm_t *as, uint op) {
|
||||
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
|
||||
}
|
||||
|
||||
// Insert word into instruction flow, add "ALWAYS" condition code
|
||||
STATIC void emit_al(asm_arm_t *as, uint op) {
|
||||
emit(as, op | ARM_CC_AL);
|
||||
}
|
||||
|
||||
// Basic instructions without condition code
|
||||
STATIC uint asm_arm_op_push(uint reglist) {
|
||||
// stmfd sp!, {reglist}
|
||||
return 0x92d0000 | (reglist & 0xFFFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_pop(uint reglist) {
|
||||
// ldmfd sp!, {reglist}
|
||||
return 0x8bd0000 | (reglist & 0xFFFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) {
|
||||
// mov rd, rn
|
||||
return 0x1a00000 | (rd << 12) | rn;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) {
|
||||
// mov rd, #imm
|
||||
return 0x3a00000 | (rd << 12) | imm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) {
|
||||
// mvn rd, #imm
|
||||
return 0x3e00000 | (rd << 12) | imm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) {
|
||||
// add rd, rn, #imm
|
||||
return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) {
|
||||
// add rd, rn, rm
|
||||
return 0x0800000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) {
|
||||
// sub rd, rn, #imm
|
||||
return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
|
||||
}
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as) {
|
||||
// bkpt #0
|
||||
emit_al(as, 0x1200070);
|
||||
}
|
||||
|
||||
// locals:
|
||||
// - stored on the stack in ascending order
|
||||
// - numbered 0 through as->num_locals-1
|
||||
// - SP points to first local
|
||||
//
|
||||
// | SP
|
||||
// v
|
||||
// l0 l1 l2 ... l(n-1)
|
||||
// ^ ^
|
||||
// | low address | high address in RAM
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals) {
|
||||
|
||||
if (num_locals < 0) {
|
||||
num_locals = 0;
|
||||
}
|
||||
|
||||
as->stack_adjust = 0;
|
||||
as->num_locals = num_locals;
|
||||
as->push_reglist = 1 << REG_R1 | 1 << REG_R2 | 1 << REG_R3 | 1 << REG_R4
|
||||
| 1 << REG_R5 | 1 << REG_R6 | 1 << REG_R7 | 1 << REG_R8;
|
||||
|
||||
// Only adjust the stack if there are more locals than usable registers
|
||||
if(num_locals > 3) {
|
||||
as->stack_adjust = num_locals * 4;
|
||||
// Align stack to 8 bytes
|
||||
if(as->num_locals & 1)
|
||||
as->stack_adjust += 4;
|
||||
}
|
||||
|
||||
emit_al(as, asm_arm_op_push(as->push_reglist | 1 << REG_LR));
|
||||
if (as->stack_adjust > 0) {
|
||||
emit_al(as, asm_arm_op_sub_imm(REG_SP, REG_SP, as->stack_adjust));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_exit(asm_arm_t *as) {
|
||||
if (as->stack_adjust > 0) {
|
||||
emit_al(as, asm_arm_op_add_imm(REG_SP, REG_SP, as->stack_adjust));
|
||||
}
|
||||
|
||||
emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << REG_PC)));
|
||||
}
|
||||
|
||||
void asm_arm_label_assign(asm_arm_t *as, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass < ASM_ARM_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
assert(as->label_offsets[label] == as->code_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_align(asm_arm_t* as, uint align) {
|
||||
// TODO fill unused data with NOPs?
|
||||
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
|
||||
}
|
||||
|
||||
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) {
|
||||
byte *c = asm_arm_get_cur_to_write_bytes(as, bytesize);
|
||||
// only write to the buffer in the emit pass (otherwise we overflow dummy_data)
|
||||
if (as->pass == ASM_ARM_PASS_EMIT) {
|
||||
// little endian
|
||||
for (uint i = 0; i < bytesize; i++) {
|
||||
*c++ = val;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {
|
||||
emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) {
|
||||
// TODO: There are more variants of immediate values
|
||||
if ((imm & 0xFF) == imm) {
|
||||
emit_al(as, asm_arm_op_mov_imm(rd, imm));
|
||||
} else if (imm < 0 && ((-imm) & 0xFF) == -imm) {
|
||||
emit_al(as, asm_arm_op_mvn_imm(rd, -imm));
|
||||
} else {
|
||||
//Insert immediate into code and jump over it
|
||||
emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc]
|
||||
emit_al(as, 0xa000000); // b pc
|
||||
emit(as, imm);
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) {
|
||||
// str rd, [sp, #local_num*4]
|
||||
emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) {
|
||||
// ldr rd, [sp, #local_num*4]
|
||||
emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) {
|
||||
// cmp rd, #imm
|
||||
emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF));
|
||||
}
|
||||
|
||||
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// cmp rd, rn
|
||||
emit_al(as, 0x1500000 | (rd << 16) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn) {
|
||||
asm_arm_cmp_reg_reg(as, rd, rn); // cmp rd, rn
|
||||
emit(as, asm_arm_op_mov_imm(REG_RET, 1) | ARM_CC_LT); // movlt REG_RET, #1
|
||||
emit(as, asm_arm_op_mov_imm(REG_RET, 0) | ARM_CC_GE); // movge REG_RET, #0
|
||||
}
|
||||
|
||||
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// add rd, rn, rm
|
||||
emit_al(as, asm_arm_op_add_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {
|
||||
// add rd, sp, #local_num*4
|
||||
emit_al(as, asm_arm_op_add_imm(rd, REG_SP, local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
int dest = as->label_offsets[label];
|
||||
int rel = dest - as->code_offset;
|
||||
rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction
|
||||
rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted
|
||||
|
||||
if (SIGNED_FIT24(rel)) {
|
||||
emit(as, cond | 0xa000000 | (rel & 0xffffff));
|
||||
} else {
|
||||
printf("asm_arm_bcc: branch does not fit in 24 bits\n");
|
||||
}
|
||||
}
|
||||
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label) {
|
||||
asm_arm_bcc_label(as, ARM_CC_AL, label);
|
||||
}
|
||||
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
|
||||
// If the table offset fits into the ldr instruction
|
||||
if(fun_id < (0x1000 / 4)) {
|
||||
emit_al(as, asm_arm_op_mov_reg(REG_LR, REG_PC)); // mov lr, pc
|
||||
emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4]
|
||||
return;
|
||||
}
|
||||
|
||||
emit_al(as, 0x59f0004 | (reg_temp << 12)); // ldr rd, [pc, #4]
|
||||
// Set lr after fun_ptr
|
||||
emit_al(as, asm_arm_op_add_imm(REG_LR, REG_PC, 4)); // add lr, pc, #4
|
||||
emit_al(as, asm_arm_op_mov_reg(REG_PC, reg_temp)); // mov pc, reg_temp
|
||||
emit(as, (uint) fun_ptr);
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_ARM
|
||||
104
py/asmarm.h
Normal file
104
py/asmarm.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Fabian Vogt
|
||||
* Copyright (c) 2013, 2014 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.
|
||||
*/
|
||||
|
||||
#define ASM_ARM_PASS_COMPUTE (1)
|
||||
#define ASM_ARM_PASS_EMIT (2)
|
||||
|
||||
#define REG_R0 (0)
|
||||
#define REG_R1 (1)
|
||||
#define REG_R2 (2)
|
||||
#define REG_R3 (3)
|
||||
#define REG_R4 (4)
|
||||
#define REG_R5 (5)
|
||||
#define REG_R6 (6)
|
||||
#define REG_R7 (7)
|
||||
#define REG_R8 (8)
|
||||
#define REG_R9 (9)
|
||||
#define REG_R10 (10)
|
||||
#define REG_R11 (11)
|
||||
#define REG_R12 (12)
|
||||
#define REG_R13 (13)
|
||||
#define REG_R14 (14)
|
||||
#define REG_R15 (15)
|
||||
#define REG_SP (REG_R13)
|
||||
#define REG_LR (REG_R14)
|
||||
#define REG_PC (REG_R15)
|
||||
|
||||
#define REG_RET REG_R0
|
||||
#define REG_ARG_1 REG_R0
|
||||
#define REG_ARG_2 REG_R1
|
||||
#define REG_ARG_3 REG_R2
|
||||
#define REG_ARG_4 REG_R3
|
||||
|
||||
#define ARM_CC_EQ (0x0 << 28)
|
||||
#define ARM_CC_NE (0x1 << 28)
|
||||
#define ARM_CC_CS (0x2 << 28)
|
||||
#define ARM_CC_CC (0x3 << 28)
|
||||
#define ARM_CC_MI (0x4 << 28)
|
||||
#define ARM_CC_PL (0x5 << 28)
|
||||
#define ARM_CC_VS (0x6 << 28)
|
||||
#define ARM_CC_VC (0x7 << 28)
|
||||
#define ARM_CC_HI (0x8 << 28)
|
||||
#define ARM_CC_LS (0x9 << 28)
|
||||
#define ARM_CC_GE (0xa << 28)
|
||||
#define ARM_CC_LT (0xb << 28)
|
||||
#define ARM_CC_GT (0xc << 28)
|
||||
#define ARM_CC_LE (0xd << 28)
|
||||
#define ARM_CC_AL (0xe << 28)
|
||||
|
||||
typedef struct _asm_arm_t asm_arm_t;
|
||||
|
||||
asm_arm_t *asm_arm_new(uint max_num_labels);
|
||||
void asm_arm_free(asm_arm_t *as, bool free_code);
|
||||
void asm_arm_start_pass(asm_arm_t *as, uint pass);
|
||||
void asm_arm_end_pass(asm_arm_t *as);
|
||||
uint asm_arm_get_code_size(asm_arm_t *as);
|
||||
void *asm_arm_get_code(asm_arm_t *as);
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals);
|
||||
void asm_arm_exit(asm_arm_t *as);
|
||||
void asm_arm_label_assign(asm_arm_t *as, uint label);
|
||||
|
||||
void asm_arm_align(asm_arm_t* as, uint align);
|
||||
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val);
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as);
|
||||
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);
|
||||
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);
|
||||
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);
|
||||
|
||||
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label);
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmthumb.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
@@ -132,8 +132,7 @@ uint asm_thumb_get_code_size(asm_thumb_t *as) {
|
||||
}
|
||||
|
||||
void *asm_thumb_get_code(asm_thumb_t *as) {
|
||||
// need to set low bit to indicate that it's thumb code
|
||||
return (void *)(((machine_uint_t)as->code_base) | 1);
|
||||
return as->code_base;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -378,7 +377,7 @@ void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) {
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32) {
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
|
||||
// movw, movt does it in 8 bytes
|
||||
// ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
|
||||
|
||||
@@ -496,17 +495,14 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
|
||||
asm_thumb_op16(as, 0x4780 | (REG_R9 << 3)); // blx reg
|
||||
*/
|
||||
|
||||
if (0) {
|
||||
// load ptr to function into register using immediate, then branch
|
||||
// not relocatable
|
||||
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
} else if (1) {
|
||||
if (fun_id < 32) {
|
||||
// load ptr to function from table, indexed by fun_id (must be in range 0-31); 4 bytes
|
||||
asm_thumb_op16(as, OP_FORMAT_9_10(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, reg_temp, REG_R7, fun_id));
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
} else {
|
||||
// use SVC
|
||||
asm_thumb_op16(as, OP_SVC(fun_id));
|
||||
// load ptr to function into register using immediate; 6 bytes
|
||||
asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
|
||||
asm_thumb_op16(as, OP_BLX(reg_temp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ void asm_thumb_ite_ge(asm_thumb_t *as);
|
||||
void asm_thumb_b_n(asm_thumb_t *as, uint label);
|
||||
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32); // convenience
|
||||
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_X64
|
||||
|
||||
8
py/bc.h
8
py/bc.h
@@ -50,11 +50,11 @@ typedef struct _mp_code_state {
|
||||
} mp_code_state;
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
void mp_bytecode_print(const void *descr, const byte *code, int len);
|
||||
void mp_bytecode_print2(const byte *code, int len);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((machine_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((machine_uint_t)(ptr) | tag))
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))
|
||||
|
||||
113
py/binary.c
113
py/binary.c
@@ -26,17 +26,22 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "binary.h"
|
||||
|
||||
// Helpers to work with binary-encoded data
|
||||
|
||||
#ifndef alignof
|
||||
#define alignof(type) offsetof(struct { char c; type t; }, t)
|
||||
#endif
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
int size = 0;
|
||||
int align = 1;
|
||||
@@ -68,16 +73,20 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
case 'b': case 'B':
|
||||
align = size = 1; break;
|
||||
case 'h': case 'H':
|
||||
align = size = sizeof(short); break;
|
||||
align = alignof(short);
|
||||
size = sizeof(short); break;
|
||||
case 'i': case 'I':
|
||||
align = size = sizeof(int); break;
|
||||
align = alignof(int);
|
||||
size = sizeof(int); break;
|
||||
case 'l': case 'L':
|
||||
align = size = sizeof(long); break;
|
||||
align = alignof(long);
|
||||
size = sizeof(long); break;
|
||||
case 'q': case 'Q':
|
||||
// TODO: This is for x86
|
||||
align = sizeof(int); size = sizeof(long long); break;
|
||||
align = alignof(long long);
|
||||
size = sizeof(long long); break;
|
||||
case 'P': case 'O': case 'S':
|
||||
align = size = sizeof(void*); break;
|
||||
align = alignof(void*);
|
||||
size = sizeof(void*); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +97,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
}
|
||||
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
machine_int_t val = 0;
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
val = ((int8_t*)p)[index];
|
||||
@@ -125,32 +134,17 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
|
||||
#define is_signed(typecode) (typecode > 'Z')
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
uint align;
|
||||
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) {
|
||||
int delta;
|
||||
if (struct_type == '<') {
|
||||
if (!big_endian) {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
|
||||
machine_int_t val = 0;
|
||||
if (is_signed(val_type) && *p & 0x80) {
|
||||
mp_int_t val = 0;
|
||||
if (is_signed && *p & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
@@ -159,7 +153,28 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
p += delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
return val;
|
||||
}
|
||||
|
||||
#define is_signed(typecode) (typecode > 'Z')
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
uint align;
|
||||
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
|
||||
|
||||
if (val_type == 'O') {
|
||||
return (mp_obj_t)val;
|
||||
} else if (val_type == 'S') {
|
||||
@@ -171,6 +186,23 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
|
||||
int in_delta, out_delta;
|
||||
if (big_endian) {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
val_ptr += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *val_ptr;
|
||||
p += out_delta;
|
||||
val_ptr += in_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
uint align;
|
||||
@@ -178,18 +210,19 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#error Not implemented
|
||||
#endif
|
||||
machine_int_t val;
|
||||
mp_int_t val;
|
||||
byte *in = (byte*)&val;
|
||||
switch (val_type) {
|
||||
case 'O':
|
||||
@@ -199,23 +232,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
val = mp_obj_get_int(val_in);
|
||||
}
|
||||
|
||||
int in_delta, out_delta;
|
||||
uint val_sz = MIN(size, sizeof(val));
|
||||
if (struct_type == '>') {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
in += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *in;
|
||||
p += out_delta;
|
||||
in += in_delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
|
||||
@@ -233,7 +250,7 @@ void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in)
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
int mp_binary_get_size(char struct_type, char val_type, uint *palign);
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val);
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
|
||||
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p);
|
||||
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr);
|
||||
|
||||
184
py/builtin.c
184
py/builtin.c
@@ -36,6 +36,8 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "stream.h"
|
||||
#include "pfenv.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
@@ -97,9 +99,9 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
|
||||
|
||||
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
if (val < 0) {
|
||||
val = -val;
|
||||
}
|
||||
@@ -113,10 +115,12 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
} else {
|
||||
return o_in;
|
||||
}
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_complex_get(o_in, &real, &imag);
|
||||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag));
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
assert(0);
|
||||
@@ -154,7 +158,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
|
||||
mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
|
||||
return mp_obj_str_format(ARRAY_SIZE(args), args);
|
||||
return mp_obj_str_format(MP_ARRAY_SIZE(args), args);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
|
||||
@@ -170,13 +174,40 @@ STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
|
||||
int ord = mp_obj_get_int(o_in);
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
mp_uint_t c = mp_obj_get_int(o_in);
|
||||
char str[4];
|
||||
int len = 0;
|
||||
if (c < 0x80) {
|
||||
*str = c; len = 1;
|
||||
} else if (c < 0x800) {
|
||||
str[0] = (c >> 6) | 0xC0;
|
||||
str[1] = (c & 0x3F) | 0x80;
|
||||
len = 2;
|
||||
} else if (c < 0x10000) {
|
||||
str[0] = (c >> 12) | 0xE0;
|
||||
str[1] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[2] = (c & 0x3F) | 0x80;
|
||||
len = 3;
|
||||
} else if (c < 0x110000) {
|
||||
str[0] = (c >> 18) | 0xF0;
|
||||
str[1] = ((c >> 12) & 0x3F) | 0x80;
|
||||
str[2] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[3] = (c & 0x3F) | 0x80;
|
||||
len = 4;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
|
||||
}
|
||||
return mp_obj_new_str(str, len, true);
|
||||
#else
|
||||
mp_int_t ord = mp_obj_get_int(o_in);
|
||||
if (0 <= ord && ord <= 0x10ffff) {
|
||||
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(0x110000)"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
|
||||
@@ -221,8 +252,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
|
||||
mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
||||
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
||||
mp_obj_t args[2];
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
|
||||
@@ -253,74 +284,50 @@ STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == NULL) {
|
||||
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)));
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_builtin_len);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t mp_builtin_min_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs, int op) {
|
||||
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP);
|
||||
mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value;
|
||||
if (n_args == 1) {
|
||||
// given an iterable
|
||||
mp_obj_t iterable = mp_getiter(args[0]);
|
||||
mp_obj_t max_obj = NULL;
|
||||
mp_obj_t best_key = MP_OBJ_NULL;
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (max_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, max_obj, item) == mp_const_true)) {
|
||||
max_obj = item;
|
||||
mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item);
|
||||
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
|
||||
best_key = key;
|
||||
best_obj = item;
|
||||
}
|
||||
}
|
||||
if (max_obj == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
|
||||
if (best_obj == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence"));
|
||||
}
|
||||
return max_obj;
|
||||
return best_obj;
|
||||
} else {
|
||||
// given many args
|
||||
mp_obj_t max_obj = args[0];
|
||||
for (int i = 1; i < n_args; i++) {
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i]) == mp_const_true) {
|
||||
max_obj = args[i];
|
||||
mp_obj_t best_key = MP_OBJ_NULL;
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]);
|
||||
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
|
||||
best_key = key;
|
||||
best_obj = args[i];
|
||||
}
|
||||
}
|
||||
return max_obj;
|
||||
return best_obj;
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_max_obj, 1, mp_builtin_max);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
// given an iterable
|
||||
mp_obj_t iterable = mp_getiter(args[0]);
|
||||
mp_obj_t min_obj = NULL;
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if (min_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, item, min_obj) == mp_const_true)) {
|
||||
min_obj = item;
|
||||
}
|
||||
}
|
||||
if (min_obj == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
|
||||
}
|
||||
return min_obj;
|
||||
} else {
|
||||
// given many args
|
||||
mp_obj_t min_obj = args[0];
|
||||
for (int i = 1; i < n_args; i++) {
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj) == mp_const_true) {
|
||||
min_obj = args[i];
|
||||
}
|
||||
}
|
||||
return min_obj;
|
||||
}
|
||||
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max);
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
|
||||
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
|
||||
mp_obj_t ret = mp_iternext_allow_raise(o);
|
||||
@@ -342,13 +349,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
|
||||
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
|
||||
uint len;
|
||||
const char *str = mp_obj_str_get_data(o_in, &len);
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
mp_uint_t charlen = unichar_charlen(str, len);
|
||||
if (charlen == 1) {
|
||||
if (MP_OBJ_IS_STR(o_in) && UTF8_IS_NONASCII(*str)) {
|
||||
mp_int_t ord = *str++ & 0x7F;
|
||||
for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
|
||||
ord &= ~mask;
|
||||
}
|
||||
while (UTF8_IS_CONT(*str)) {
|
||||
ord = (ord << 6) | (*str++ & 0x3F);
|
||||
}
|
||||
return mp_obj_new_int(ord);
|
||||
} else {
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
}
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", charlen));
|
||||
}
|
||||
#else
|
||||
if (len == 1) {
|
||||
// don't sign extend when converting to ord
|
||||
// TODO unicode
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
|
||||
@@ -376,13 +402,36 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
|
||||
if (end_elem != NULL && end_elem->value != mp_const_none) {
|
||||
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_t stream_obj = &mp_sys_stdout_obj;
|
||||
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
|
||||
if (file_elem != NULL && file_elem->value != mp_const_none) {
|
||||
stream_obj = file_elem->value;
|
||||
}
|
||||
|
||||
pfenv_t pfenv;
|
||||
pfenv.data = stream_obj;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
|
||||
#endif
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, sep_data, sep_len);
|
||||
#else
|
||||
printf("%.*s", sep_len, sep_data);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
|
||||
#else
|
||||
mp_obj_print(args[i], PRINT_STR);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, end_data, end_len);
|
||||
#else
|
||||
printf("%.*s", end_len, end_data);
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@@ -430,7 +479,21 @@ STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *k
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) {
|
||||
return mp_obj_new_int((machine_int_t)o_in);
|
||||
mp_int_t id = (mp_int_t)o_in;
|
||||
if (!MP_OBJ_IS_OBJ(o_in)) {
|
||||
return mp_obj_new_int(id);
|
||||
} else if (id >= 0) {
|
||||
// Many OSes and CPUs have affinity for putting "user" memories
|
||||
// into low half of address space, and "system" into upper half.
|
||||
// We're going to take advantage of that and return small int
|
||||
// (signed) for such "user" addresses.
|
||||
return MP_OBJ_NEW_SMALL_INT(id);
|
||||
} else {
|
||||
// If that didn't work, well, let's return long int, just as
|
||||
// a (big) positve value, so it will never clash with the range
|
||||
// of small int returned in previous case.
|
||||
return mp_obj_new_int_from_uint((mp_uint_t)id);
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id);
|
||||
@@ -482,6 +545,7 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
|
||||
|
||||
// These two are defined in terms of MicroPython API functions right away
|
||||
// These are defined in terms of MicroPython API functions right away
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get);
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get);
|
||||
|
||||
10
py/builtin.h
10
py/builtin.h
@@ -26,6 +26,7 @@
|
||||
|
||||
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_len(mp_obj_t o);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -80,3 +81,12 @@ extern const mp_obj_module_t mp_module_micropython;
|
||||
extern const mp_obj_module_t mp_module_struct;
|
||||
extern const mp_obj_module_t mp_module_sys;
|
||||
extern const mp_obj_module_t mp_module_gc;
|
||||
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
extern const mp_obj_module_t mp_module_zlibd;
|
||||
|
||||
@@ -120,6 +120,9 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// set the new context
|
||||
mp_locals_set(mp_obj_module_get_globals(module_obj));
|
||||
mp_globals_set(mp_obj_module_get_globals(module_obj));
|
||||
#if MICROPY_PY___FILE__
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false));
|
||||
#endif
|
||||
|
||||
// parse the imported script
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -43,8 +43,10 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
// built-in types
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes },
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dict), (mp_obj_t)&mp_type_dict },
|
||||
@@ -64,6 +66,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_range), (mp_obj_t)&mp_type_range },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reversed), (mp_obj_t)&mp_type_reversed },
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&mp_type_set },
|
||||
#endif
|
||||
@@ -135,6 +138,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ZeroDivisionError), (mp_obj_t)&mp_type_ZeroDivisionError },
|
||||
@@ -150,8 +154,8 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_object_table,
|
||||
},
|
||||
};
|
||||
@@ -160,7 +164,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
|
||||
#endif
|
||||
#if MICROPY_PY_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
@@ -186,6 +192,15 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
|
||||
#endif
|
||||
|
||||
// extmod modules
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
#if MICROPY_PY_ZLIBD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
|
||||
#endif
|
||||
|
||||
// extra builtin modules as defined by a port
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
};
|
||||
@@ -195,8 +210,8 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_table,
|
||||
},
|
||||
};
|
||||
|
||||
213
py/compile.c
213
py/compile.c
@@ -31,8 +31,8 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -48,8 +48,6 @@
|
||||
|
||||
// TODO need to mangle __attr names
|
||||
|
||||
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
|
||||
|
||||
typedef enum {
|
||||
PN_none = 0,
|
||||
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
|
||||
@@ -95,7 +93,7 @@ typedef struct _compiler_t {
|
||||
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
|
||||
// TODO store the error message to a variable in compiler_t instead of printing it
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (machine_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
} else {
|
||||
printf(" File \"%s\"\n", qstr_str(comp->source_file));
|
||||
}
|
||||
@@ -104,6 +102,9 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
// Extra constants as defined by a port
|
||||
MICROPY_PORT_CONSTANTS
|
||||
};
|
||||
@@ -111,8 +112,8 @@ STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
STATIC const mp_map_t mp_constants_map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = ARRAY_SIZE(mp_constants_table),
|
||||
.used = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.table = (mp_map_elem_t*)mp_constants_table,
|
||||
};
|
||||
|
||||
@@ -158,7 +159,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "constant must be an integer");
|
||||
break;
|
||||
}
|
||||
machine_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
|
||||
// store the value in the table of dynamic constants
|
||||
mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(id_qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
@@ -200,8 +201,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int | int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
|
||||
}
|
||||
break;
|
||||
@@ -209,16 +210,16 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_and_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int & int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_shift_expr:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
|
||||
// int << int
|
||||
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
|
||||
@@ -235,10 +236,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
break;
|
||||
|
||||
case PN_arith_expr:
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than mp_int_t
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
|
||||
// int + int
|
||||
arg0 += arg1;
|
||||
@@ -258,8 +259,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_term:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
|
||||
// int * int
|
||||
if (!mp_small_int_mul_overflow(arg0, arg1)) {
|
||||
@@ -288,7 +289,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_factor_2:
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
|
||||
// +int
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
|
||||
@@ -336,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(elem->value, q_attr, dest);
|
||||
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
|
||||
machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_SMALL_INT_FITS(val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
@@ -351,7 +352,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
}
|
||||
|
||||
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
|
||||
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
|
||||
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
|
||||
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
|
||||
|
||||
STATIC uint comp_next_label(compiler_t *comp) {
|
||||
@@ -482,7 +483,7 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len,
|
||||
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (machine_uint_t)pns->nodes[1], false);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -726,9 +727,9 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
|
||||
}
|
||||
|
||||
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
|
||||
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
|
||||
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
|
||||
|
||||
void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
|
||||
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
|
||||
if (assign_kind != ASSIGN_AUG_STORE) {
|
||||
compile_node(comp, pns->nodes[0]);
|
||||
}
|
||||
@@ -789,7 +790,7 @@ cannot_assign:
|
||||
}
|
||||
|
||||
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
|
||||
void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
|
||||
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
|
||||
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
|
||||
|
||||
// look for star expression
|
||||
@@ -829,7 +830,7 @@ void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail,
|
||||
}
|
||||
|
||||
// assigns top of stack to pn
|
||||
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
|
||||
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
|
||||
tail_recursion:
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
assert(0);
|
||||
@@ -944,7 +945,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
|
||||
// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults
|
||||
// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults
|
||||
// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)
|
||||
void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
|
||||
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
|
||||
assert(n_pos_defaults >= 0);
|
||||
assert(n_kw_defaults >= 0);
|
||||
|
||||
@@ -979,7 +980,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
|
||||
}
|
||||
}
|
||||
|
||||
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
|
||||
comp->have_star = true;
|
||||
/* don't need to distinguish bare from named star
|
||||
@@ -1251,7 +1252,7 @@ void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
EMIT_ARG(store_id, fname);
|
||||
}
|
||||
|
||||
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
|
||||
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
EMIT_ARG(delete_id, MP_PARSE_NODE_LEAF_ARG(pn));
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
|
||||
@@ -1403,7 +1404,7 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// q_base holds the base of the name
|
||||
// eg a -> q_base=a
|
||||
// a.b.c -> q_base=a
|
||||
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
|
||||
STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
|
||||
bool is_as = false;
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
@@ -1463,7 +1464,7 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
|
||||
}
|
||||
}
|
||||
|
||||
void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
|
||||
STATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
|
||||
EMIT_ARG(load_const_small_int, 0); // level 0 import
|
||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything
|
||||
qstr q_base;
|
||||
@@ -1742,10 +1743,11 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
EMIT_ARG(label_assign, break_label);
|
||||
}
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// TODO preload end and step onto stack if they are not constants
|
||||
// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
|
||||
// And, if the loop never runs, the loop variable should never be assigned
|
||||
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
||||
STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
// note that we don't need to pop anything when breaking from an optimise for loop
|
||||
|
||||
@@ -1798,6 +1800,7 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
|
||||
|
||||
EMIT_ARG(label_assign, break_label);
|
||||
}
|
||||
#endif
|
||||
|
||||
void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
@@ -1881,7 +1884,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
EMIT_ARG(label_assign, end_label);
|
||||
}
|
||||
|
||||
void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
|
||||
STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
|
||||
// setup code
|
||||
uint l1 = comp_next_label(comp);
|
||||
uint success_label = comp_next_label(comp);
|
||||
@@ -1894,7 +1897,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
EMIT_ARG(jump, success_label); // jump over exception handler
|
||||
|
||||
EMIT_ARG(label_assign, l1); // start of exception handler
|
||||
EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
EMIT(start_except_handler);
|
||||
|
||||
uint l2 = comp_next_label(comp);
|
||||
|
||||
@@ -1966,14 +1969,14 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
|
||||
compile_decrease_except_level(comp);
|
||||
EMIT(end_finally);
|
||||
EMIT_ARG(adjust_stack_size, -5); // stack adjust
|
||||
EMIT(end_except_handler);
|
||||
|
||||
EMIT_ARG(label_assign, success_label);
|
||||
compile_node(comp, pn_else); // else block, can be null
|
||||
EMIT_ARG(label_assign, l2);
|
||||
}
|
||||
|
||||
void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
|
||||
STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
|
||||
uint l_finally_block = comp_next_label(comp);
|
||||
|
||||
EMIT_ARG(setup_finally, l_finally_block);
|
||||
@@ -2025,7 +2028,7 @@ void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
}
|
||||
|
||||
void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
|
||||
STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
|
||||
if (n == 0) {
|
||||
// no more pre-bits, compile the body of the with
|
||||
compile_node(comp, body);
|
||||
@@ -2175,7 +2178,7 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
}
|
||||
|
||||
void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
|
||||
STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
|
||||
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
compile_node(comp, pns->nodes[0]);
|
||||
for (int i = 1; i < num_nodes; i += 1) {
|
||||
@@ -2528,7 +2531,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
|
||||
pn_kind = MP_PARSE_NODE_STRING;
|
||||
n_bytes += (machine_uint_t)pns_string->nodes[1];
|
||||
n_bytes += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
if (i == 0) {
|
||||
string_kind = pn_kind;
|
||||
@@ -2549,8 +2552,8 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
s_dest += s_len;
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
memcpy(s_dest, (const char*)pns_string->nodes[0], (machine_uint_t)pns_string->nodes[1]);
|
||||
s_dest += (machine_uint_t)pns_string->nodes[1];
|
||||
memcpy(s_dest, (const char*)pns_string->nodes[0], (mp_uint_t)pns_string->nodes[1]);
|
||||
s_dest += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
}
|
||||
qstr q = qstr_build_end(q_ptr);
|
||||
@@ -2559,7 +2562,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
|
||||
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
|
||||
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
|
||||
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
|
||||
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));
|
||||
mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1];
|
||||
@@ -2854,14 +2857,14 @@ STATIC compile_function_t compile_function[] = {
|
||||
#undef DEF_RULE
|
||||
};
|
||||
|
||||
void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
// pass
|
||||
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
EMIT_ARG(load_const_small_int, arg);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
|
||||
case MP_PARSE_NODE_INTEGER: EMIT_ARG(load_const_int, arg); break;
|
||||
@@ -2883,7 +2886,7 @@ 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_line_number, pns->source_line);
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
|
||||
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (machine_uint_t)pns->nodes[1]), false);
|
||||
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
|
||||
} else {
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
@@ -2899,11 +2902,10 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
}
|
||||
}
|
||||
|
||||
void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star, bool allow_annotations) {
|
||||
STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) {
|
||||
// TODO verify that *k and **k are last etc
|
||||
qstr param_name = MP_QSTR_NULL;
|
||||
uint param_flag = ID_FLAG_IS_PARAM;
|
||||
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
if (comp->have_star) {
|
||||
@@ -2918,24 +2920,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) {
|
||||
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||
//int node_index = 1; unused
|
||||
if (allow_annotations) {
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||
// this parameter has an annotation
|
||||
pn_annotation = pns->nodes[1];
|
||||
}
|
||||
//node_index = 2; unused
|
||||
}
|
||||
/* this is obsolete now that num dict/default params are calculated in compile_funcdef_param
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[node_index])) {
|
||||
// this parameter has a default value
|
||||
if (comp->have_star) {
|
||||
comp->scope_cur->num_dict_params += 1;
|
||||
} else {
|
||||
comp->scope_cur->num_default_params += 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (comp->have_star) {
|
||||
// comes after a star, so counts as a keyword-only parameter
|
||||
comp->scope_cur->num_kwonly_args += 1;
|
||||
@@ -2954,12 +2938,11 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
||||
// named star
|
||||
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
|
||||
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||
} else if (allow_annotations && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
|
||||
// named star with possible annotation
|
||||
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
|
||||
pns = (mp_parse_node_struct_t*)pns->nodes[0];
|
||||
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||
pn_annotation = pns->nodes[1];
|
||||
} else {
|
||||
// shouldn't happen
|
||||
assert(0);
|
||||
@@ -2967,10 +2950,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
|
||||
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
|
||||
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||
// this parameter has an annotation
|
||||
pn_annotation = pns->nodes[1];
|
||||
}
|
||||
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS;
|
||||
} else {
|
||||
// TODO anything to implement?
|
||||
@@ -2979,9 +2958,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
||||
}
|
||||
|
||||
if (param_name != MP_QSTR_NULL) {
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
|
||||
// TODO this parameter has an annotation
|
||||
}
|
||||
bool added;
|
||||
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added);
|
||||
if (!added) {
|
||||
@@ -2994,14 +2970,61 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
||||
}
|
||||
|
||||
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
|
||||
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star);
|
||||
}
|
||||
|
||||
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
|
||||
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star);
|
||||
}
|
||||
|
||||
void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
|
||||
STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
// no annotation
|
||||
return;
|
||||
}
|
||||
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_name) {
|
||||
// named parameter with possible annotation
|
||||
// fallthrough
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_star) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
|
||||
// named star with possible annotation
|
||||
pns = (mp_parse_node_struct_t*)pns->nodes[0];
|
||||
// fallthrough
|
||||
} else {
|
||||
// no annotation
|
||||
return;
|
||||
}
|
||||
} else if (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];
|
||||
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
qstr param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||
id_info_t *id_info = scope_find(comp->scope_cur, param_name);
|
||||
assert(id_info != NULL);
|
||||
|
||||
if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER) {
|
||||
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
|
||||
qstr arg_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
|
||||
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type);
|
||||
} else {
|
||||
compile_syntax_error(comp, pn_annotation, "parameter annotation must be an identifier");
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
|
||||
tail_recursion:
|
||||
if (MP_PARSE_NODE_IS_NULL(pn_iter)) {
|
||||
// no more nested if/for; compile inner expression
|
||||
@@ -3125,9 +3148,28 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
comp->have_star = false;
|
||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
|
||||
}
|
||||
} else {
|
||||
// compile annotations; only needed on latter compiler passes
|
||||
|
||||
// pns->nodes[2] is return/whole function annotation
|
||||
// argument annotations
|
||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_annotations);
|
||||
|
||||
// pns->nodes[2] is return/whole function annotation
|
||||
mp_parse_node_t pn_annotation = pns->nodes[2];
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (scope->emit_options == MP_EMIT_OPT_VIPER) {
|
||||
// nodes[2] can be null or a test-expr
|
||||
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
|
||||
qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
|
||||
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type);
|
||||
} else {
|
||||
compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier");
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
}
|
||||
}
|
||||
|
||||
compile_node(comp, pns->nodes[3]); // 3 is function body
|
||||
// emit return if it wasn't the last opcode
|
||||
@@ -3337,7 +3379,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
return;
|
||||
}
|
||||
if (pass > MP_PASS_SCOPE) {
|
||||
machine_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
|
||||
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
|
||||
@@ -3584,9 +3626,14 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
emit_native = emit_native_thumb_new(max_num_labels);
|
||||
}
|
||||
comp->emit_method_table = &emit_native_thumb_method_table;
|
||||
#elif MICROPY_EMIT_ARM
|
||||
if (emit_native == NULL) {
|
||||
emit_native = emit_native_arm_new(max_num_labels);
|
||||
}
|
||||
comp->emit_method_table = &emit_native_arm_method_table;
|
||||
#endif
|
||||
comp->emit = emit_native;
|
||||
comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
|
||||
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0);
|
||||
|
||||
// native emitters need an extra pass to compute stack size
|
||||
compile_scope(comp, s, MP_PASS_STACK_SIZE);
|
||||
@@ -3627,6 +3674,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
emit_native_x64_free(emit_native);
|
||||
#elif MICROPY_EMIT_THUMB
|
||||
emit_native_thumb_free(emit_native);
|
||||
#elif MICROPY_EMIT_ARM
|
||||
emit_native_arm_free(emit_native);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
16
py/emit.h
16
py/emit.h
@@ -46,10 +46,14 @@ typedef enum {
|
||||
|
||||
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
|
||||
|
||||
#define MP_EMIT_NATIVE_TYPE_ENABLE (0)
|
||||
#define MP_EMIT_NATIVE_TYPE_RETURN (1)
|
||||
#define MP_EMIT_NATIVE_TYPE_ARG (2)
|
||||
|
||||
typedef struct _emit_t emit_t;
|
||||
|
||||
typedef struct _emit_method_table_t {
|
||||
void (*set_native_types)(emit_t *emit, bool do_native_types);
|
||||
void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2);
|
||||
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
|
||||
void (*end_pass)(emit_t *emit);
|
||||
bool (*last_emit_was_return_value)(emit_t *emit);
|
||||
@@ -65,7 +69,7 @@ typedef struct _emit_method_table_t {
|
||||
void (*import_from)(emit_t *emit, qstr qstr);
|
||||
void (*import_star)(emit_t *emit);
|
||||
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
|
||||
void (*load_const_small_int)(emit_t *emit, machine_int_t arg);
|
||||
void (*load_const_small_int)(emit_t *emit, mp_int_t arg);
|
||||
void (*load_const_int)(emit_t *emit, qstr qstr);
|
||||
void (*load_const_dec)(emit_t *emit, qstr qstr);
|
||||
void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes);
|
||||
@@ -134,6 +138,11 @@ typedef struct _emit_method_table_t {
|
||||
void (*yield_value)(emit_t *emit);
|
||||
void (*yield_from)(emit_t *emit);
|
||||
|
||||
// these methods are used to control entry to/exit from an exception handler
|
||||
// they may or may not emit code
|
||||
void (*start_except_handler)(emit_t *emit);
|
||||
void (*end_except_handler)(emit_t *emit);
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// these methods are only needed for emitcpy
|
||||
void (*load_const_verbatim_str)(emit_t *emit, const char *str);
|
||||
@@ -152,17 +161,20 @@ extern const emit_method_table_t emit_cpython_method_table;
|
||||
extern const emit_method_table_t emit_bc_method_table;
|
||||
extern const emit_method_table_t emit_native_x64_method_table;
|
||||
extern const emit_method_table_t emit_native_thumb_method_table;
|
||||
extern const emit_method_table_t emit_native_arm_method_table;
|
||||
|
||||
emit_t *emit_pass1_new(void);
|
||||
emit_t *emit_cpython_new(uint max_num_labels);
|
||||
emit_t *emit_bc_new(uint max_num_labels);
|
||||
emit_t *emit_native_x64_new(uint max_num_labels);
|
||||
emit_t *emit_native_thumb_new(uint max_num_labels);
|
||||
emit_t *emit_native_arm_new(uint max_num_labels);
|
||||
|
||||
void emit_pass1_free(emit_t *emit);
|
||||
void emit_bc_free(emit_t *emit);
|
||||
void emit_native_x64_free(emit_t *emit);
|
||||
void emit_native_thumb_free(emit_t *emit);
|
||||
void emit_native_arm_free(emit_t *emit);
|
||||
|
||||
typedef struct _emit_inline_asm_t emit_inline_asm_t;
|
||||
|
||||
|
||||
55
py/emitbc.c
55
py/emitbc.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -50,7 +50,6 @@
|
||||
struct _emit_t {
|
||||
pass_kind_t pass : 8;
|
||||
uint last_emit_was_return_value : 8;
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
|
||||
int stack_size;
|
||||
|
||||
@@ -67,6 +66,8 @@ struct _emit_t {
|
||||
uint bytecode_offset;
|
||||
uint bytecode_size;
|
||||
byte *code_base; // stores both byte code and code info
|
||||
// Accessed as uint, so must be aligned as such
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
};
|
||||
|
||||
STATIC void emit_bc_rot_two(emit_t *emit);
|
||||
@@ -99,7 +100,7 @@ STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_writ
|
||||
}
|
||||
|
||||
STATIC void emit_align_code_info_to_machine_word(emit_t* emit) {
|
||||
emit->code_info_offset = (emit->code_info_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
emit->code_info_offset = (emit->code_info_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
|
||||
@@ -114,12 +115,24 @@ STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
STATIC void emit_write_code_info_bytes_lines(emit_t* emit, uint bytes_to_skip, uint lines_to_skip) {
|
||||
assert(bytes_to_skip > 0 || lines_to_skip > 0);
|
||||
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
|
||||
while (bytes_to_skip > 0 || lines_to_skip > 0) {
|
||||
uint b = MIN(bytes_to_skip, 31);
|
||||
uint l = MIN(lines_to_skip, 7);
|
||||
mp_uint_t b, l;
|
||||
if (lines_to_skip <= 6) {
|
||||
// use 0b0LLBBBBB encoding
|
||||
b = MIN(bytes_to_skip, 0x1f);
|
||||
l = MIN(lines_to_skip, 0x3);
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
} else {
|
||||
// use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
|
||||
b = MIN(bytes_to_skip, 0xf);
|
||||
l = MIN(lines_to_skip, 0x7ff);
|
||||
byte *ci = emit_get_cur_to_write_code_info(emit, 2);
|
||||
ci[0] = 0x80 | b | ((l >> 4) & 0x70);
|
||||
ci[1] = l;
|
||||
}
|
||||
bytes_to_skip -= b;
|
||||
lines_to_skip -= l;
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -139,7 +152,7 @@ STATIC byte* emit_get_cur_to_write_bytecode(emit_t* emit, int num_bytes_to_write
|
||||
}
|
||||
|
||||
STATIC void emit_align_bytecode_to_machine_word(emit_t* emit) {
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
|
||||
@@ -171,7 +184,7 @@ STATIC void emit_write_bytecode_uint(emit_t* emit, uint num) {
|
||||
}
|
||||
|
||||
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
|
||||
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, machine_int_t num) {
|
||||
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
|
||||
emit_write_bytecode_byte(emit, b1);
|
||||
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
@@ -206,8 +219,10 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, uint num) {
|
||||
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
emit_align_bytecode_to_machine_word(emit);
|
||||
machine_uint_t *c = (machine_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(machine_uint_t));
|
||||
*c = (machine_uint_t)ptr;
|
||||
mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
|
||||
// Verify thar c is already uint-aligned
|
||||
assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
|
||||
*c = (mp_uint_t)ptr;
|
||||
}
|
||||
|
||||
/* currently unused
|
||||
@@ -250,7 +265,7 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint la
|
||||
c[2] = bytecode_offset >> 8;
|
||||
}
|
||||
|
||||
STATIC void emit_bc_set_native_types(emit_t *emit, bool do_native_types) {
|
||||
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
@@ -269,7 +284,7 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
// write code info size; use maximum space (4 bytes) to write it; TODO possible optimise this
|
||||
{
|
||||
byte* c = emit_get_cur_to_write_code_info(emit, 4);
|
||||
machine_uint_t s = emit->code_info_size;
|
||||
mp_uint_t s = emit->code_info_size;
|
||||
c[0] = s & 0xff;
|
||||
c[1] = (s >> 8) & 0xff;
|
||||
c[2] = (s >> 16) & 0xff;
|
||||
@@ -360,7 +375,6 @@ STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
|
||||
uint bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
|
||||
uint lines_to_skip = source_line - emit->last_source_line;
|
||||
emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
|
||||
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
|
||||
emit->last_source_line_offset = emit->bytecode_offset;
|
||||
emit->last_source_line = source_line;
|
||||
}
|
||||
@@ -428,7 +442,7 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
}
|
||||
@@ -849,8 +863,16 @@ STATIC void emit_bc_yield_from(emit_t *emit) {
|
||||
emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
}
|
||||
|
||||
STATIC void emit_bc_end_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_set_native_types,
|
||||
emit_bc_set_native_type,
|
||||
emit_bc_start_pass,
|
||||
emit_bc_end_pass,
|
||||
emit_bc_last_emit_was_return_value,
|
||||
@@ -934,6 +956,9 @@ const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_raise_varargs,
|
||||
emit_bc_yield_value,
|
||||
emit_bc_yield_from,
|
||||
|
||||
emit_bc_start_except_handler,
|
||||
emit_bc_end_except_handler,
|
||||
};
|
||||
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
|
||||
19
py/emitcpy.c
19
py/emitcpy.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -63,7 +63,7 @@ emit_t *emit_cpython_new(uint max_num_labels) {
|
||||
return emit;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_native_types(emit_t *emit, bool do_native_types) {
|
||||
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
@@ -173,7 +173,7 @@ STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST " INT_FMT "\n", arg);
|
||||
@@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
@@ -814,7 +822,7 @@ STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_set_native_types,
|
||||
emit_cpy_set_native_type,
|
||||
emit_cpy_start_pass,
|
||||
emit_cpy_end_pass,
|
||||
emit_cpy_last_emit_was_return_value,
|
||||
@@ -899,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_yield_value,
|
||||
emit_cpy_yield_from,
|
||||
|
||||
emit_cpy_start_except_handler,
|
||||
emit_cpy_end_except_handler,
|
||||
|
||||
// emitcpy specific functions
|
||||
emit_cpy_load_const_verbatim_str,
|
||||
emit_cpy_load_closure,
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -55,7 +55,7 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags) {
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) {
|
||||
rc->kind = MP_CODE_BYTECODE;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
@@ -65,7 +65,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
|
||||
rc->u_byte.len = len;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
|
||||
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
|
||||
DEBUG_printf(" arg names:");
|
||||
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
|
||||
DEBUG_printf(" %s", qstr_str(arg_names[i]));
|
||||
@@ -74,7 +74,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
|
||||
#endif
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
if (mp_verbose_flag > 0) {
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
@@ -86,31 +86,33 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun, uint len, int n_args) {
|
||||
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
|
||||
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = 0;
|
||||
rc->n_pos_args = n_args;
|
||||
rc->u_native.fun = fun;
|
||||
rc->u_native.fun_data = fun_data;
|
||||
rc->u_native.type_sig = type_sig;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=%u n_args=%d\n", kind, fun, len, n_args);
|
||||
byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
|
||||
for (mp_uint_t i = 0; i < fun_len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
DEBUG_printf(" %02x", fun_data[i]);
|
||||
DEBUG_printf(" %02x", ((byte*)fun_data)[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
|
||||
#ifdef WRITE_CODE
|
||||
FILE *fp_write_code = fopen("out-code", "wb");
|
||||
fwrite(fun_data, len, 1, fp_write_code);
|
||||
fwrite(fun_data, fun_len, 1, fp_write_code);
|
||||
fclose(fp_write_code);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
|
||||
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
|
||||
@@ -128,13 +130,19 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
case MP_CODE_BYTECODE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
|
||||
break;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
case MP_CODE_NATIVE_PY:
|
||||
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
|
||||
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
|
||||
break;
|
||||
case MP_CODE_NATIVE_VIPER:
|
||||
case MP_CODE_NATIVE_ASM:
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun);
|
||||
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->u_native.type_sig);
|
||||
break;
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
case MP_CODE_NATIVE_ASM:
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun_data);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// raw code was never set (this should not happen)
|
||||
assert(0);
|
||||
@@ -149,8 +157,8 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
return fun;
|
||||
}
|
||||
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
|
||||
DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
|
||||
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
|
||||
// make function object
|
||||
mp_obj_t ffun;
|
||||
if (n_closed_over & 0x100) {
|
||||
|
||||
@@ -37,25 +37,26 @@ typedef enum {
|
||||
|
||||
typedef struct _mp_code_t {
|
||||
mp_raw_code_kind_t kind : 3;
|
||||
uint scope_flags : 7;
|
||||
uint n_pos_args : 11;
|
||||
uint n_kwonly_args : 11;
|
||||
mp_uint_t scope_flags : 7;
|
||||
mp_uint_t n_pos_args : 11;
|
||||
mp_uint_t n_kwonly_args : 11;
|
||||
qstr *arg_names;
|
||||
union {
|
||||
struct {
|
||||
byte *code;
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
} u_byte;
|
||||
struct {
|
||||
void *fun;
|
||||
void *fun_data;
|
||||
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
|
||||
} u_native;
|
||||
};
|
||||
} mp_raw_code_t;
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
|
||||
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *f, uint len, int n_args);
|
||||
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags);
|
||||
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
|
||||
|
||||
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
|
||||
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -99,7 +99,7 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
|
||||
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
void *f = asm_thumb_get_code(emit->as);
|
||||
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
|
||||
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
|
||||
}
|
||||
|
||||
return emit->success;
|
||||
@@ -167,7 +167,7 @@ STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
const char *reg_str = qstr_str(reg_qstr);
|
||||
for (uint i = 0; i < ARRAY_SIZE(reg_name_table); i++) {
|
||||
for (uint i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
|
||||
const reg_name_t *r = ®_name_table[i];
|
||||
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
|
||||
if (r->reg > max_reg) {
|
||||
@@ -286,7 +286,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
asm_thumb_b_n(emit->as, label_num);
|
||||
} else if (op_str[0] == 'b' && op_len == 3) {
|
||||
uint cc = -1;
|
||||
for (uint i = 0; i < ARRAY_SIZE(cc_name_table); i++) {
|
||||
for (uint i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
|
||||
if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
|
||||
cc = cc_name_table[i].cc;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
|
||||
uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
|
||||
asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
|
||||
} else if (strcmp(op_str, "and") == 0) {
|
||||
} else if (strcmp(op_str, "and_") == 0) {
|
||||
op_code = ASM_THUMB_FORMAT_4_AND;
|
||||
uint reg_dest, reg_src;
|
||||
op_format_4:
|
||||
@@ -323,7 +323,6 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
|
||||
reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
|
||||
asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
|
||||
// TODO probably uses less ROM if these ops are in a lookup table
|
||||
} else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
|
||||
} else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;
|
||||
|
||||
609
py/emitnative.c
609
py/emitnative.c
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -214,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = {
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
@@ -75,7 +75,7 @@ int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char s
|
||||
|
||||
if (buf_size < 7) {
|
||||
// Smallest exp notion is -9e+99 which is 6 chars plus terminating
|
||||
// nulll.
|
||||
// null.
|
||||
|
||||
if (buf_size >= 2) {
|
||||
*s++ = '?';
|
||||
|
||||
234
py/gc.c
234
py/gc.c
@@ -33,7 +33,6 @@
|
||||
#include "misc.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -47,22 +46,26 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
// make this 1 to dump the heap each time it changes
|
||||
#define EXTENSIVE_HEAP_PROFILING (0)
|
||||
|
||||
#define WORDS_PER_BLOCK (4)
|
||||
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
|
||||
#define STACK_SIZE (64) // tunable; minimum is 1
|
||||
|
||||
STATIC byte *gc_alloc_table_start;
|
||||
STATIC machine_uint_t gc_alloc_table_byte_len;
|
||||
STATIC mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
STATIC byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
STATIC machine_uint_t *gc_pool_start;
|
||||
STATIC machine_uint_t *gc_pool_end;
|
||||
STATIC mp_uint_t *gc_pool_start;
|
||||
STATIC mp_uint_t *gc_pool_end;
|
||||
|
||||
STATIC int gc_stack_overflow;
|
||||
STATIC machine_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC machine_uint_t *gc_sp;
|
||||
STATIC machine_uint_t gc_lock_depth;
|
||||
STATIC mp_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC mp_uint_t *gc_sp;
|
||||
STATIC mp_uint_t gc_lock_depth;
|
||||
STATIC mp_uint_t gc_last_free_atb_index;
|
||||
|
||||
// ATB = allocation table byte
|
||||
// 0b00 = FREE -- free block
|
||||
@@ -94,8 +97,8 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
|
||||
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (machine_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (machine_uint_t)gc_pool_start))
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
|
||||
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -112,32 +115,35 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
|
||||
void gc_init(void *start, void *end) {
|
||||
// align end pointer on block boundary
|
||||
end = (void*)((machine_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, end - start);
|
||||
end = (void*)((mp_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
|
||||
|
||||
// calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
|
||||
// T = A + F + P
|
||||
// F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
|
||||
// P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
|
||||
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
|
||||
machine_uint_t total_byte_len = end - start;
|
||||
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
|
||||
#else
|
||||
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
|
||||
#endif
|
||||
|
||||
|
||||
gc_alloc_table_start = (byte*)start;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
machine_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB;
|
||||
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
|
||||
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
|
||||
#endif
|
||||
|
||||
machine_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = end - gc_pool_block_len * BYTES_PER_BLOCK;
|
||||
gc_pool_end = end;
|
||||
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
|
||||
gc_pool_end = (mp_uint_t*)end;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// clear ATBs
|
||||
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
|
||||
@@ -154,6 +160,9 @@ void gc_init(void *start, void *end) {
|
||||
gc_pool_start[i] = 0;
|
||||
}
|
||||
|
||||
// set last free ATB index to start of heap
|
||||
gc_last_free_atb_index = 0;
|
||||
|
||||
// unlock the GC
|
||||
gc_lock_depth = 0;
|
||||
|
||||
@@ -173,16 +182,20 @@ void gc_unlock(void) {
|
||||
gc_lock_depth--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return gc_lock_depth != 0;
|
||||
}
|
||||
|
||||
#define VERIFY_PTR(ptr) ( \
|
||||
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
||||
&& ptr >= (machine_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (machine_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
)
|
||||
|
||||
#define VERIFY_MARK_AND_PUSH(ptr) \
|
||||
do { \
|
||||
if (VERIFY_PTR(ptr)) { \
|
||||
machine_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
mp_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
if (ATB_GET_KIND(_block) == AT_HEAD) { \
|
||||
/* an unmarked head, mark it, and push it on gc stack */ \
|
||||
ATB_HEAD_TO_MARK(_block); \
|
||||
@@ -198,18 +211,18 @@ void gc_unlock(void) {
|
||||
STATIC void gc_drain_stack(void) {
|
||||
while (gc_sp > gc_stack) {
|
||||
// pop the next block off the stack
|
||||
machine_uint_t block = *--gc_sp;
|
||||
mp_uint_t block = *--gc_sp;
|
||||
|
||||
// work out number of consecutive blocks in the chain starting with this one
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
|
||||
// check this block's children
|
||||
machine_uint_t *scan = (machine_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (machine_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
machine_uint_t ptr2 = *scan;
|
||||
mp_uint_t *scan = (mp_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (mp_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
mp_uint_t ptr2 = *scan;
|
||||
VERIFY_MARK_AND_PUSH(ptr2);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +234,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
gc_sp = gc_stack;
|
||||
|
||||
// scan entire memory looking for blocks which have been marked but not their children
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
// trace (again) if mark bit set
|
||||
if (ATB_GET_KIND(block) == AT_MARK) {
|
||||
*gc_sp++ = block;
|
||||
@@ -241,7 +254,7 @@ STATIC void gc_sweep(void) {
|
||||
#endif
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
switch (ATB_GET_KIND(block)) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -268,6 +281,7 @@ STATIC void gc_sweep(void) {
|
||||
|
||||
case AT_TAIL:
|
||||
if (free_tail) {
|
||||
DEBUG_printf("gc_sweep(%p)\n",PTR_FROM_BLOCK(block));
|
||||
ATB_ANY_TO_FREE(block);
|
||||
}
|
||||
break;
|
||||
@@ -286,9 +300,9 @@ void gc_collect_start(void) {
|
||||
gc_sp = gc_stack;
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
for (machine_uint_t i = 0; i < len; i++) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptrs[i];
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
VERIFY_MARK_AND_PUSH(ptr);
|
||||
gc_drain_stack();
|
||||
}
|
||||
@@ -297,18 +311,19 @@ void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep();
|
||||
gc_last_free_atb_index = 0;
|
||||
gc_unlock();
|
||||
}
|
||||
|
||||
void gc_info(gc_info_t *info) {
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(machine_uint_t);
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
|
||||
info->used = 0;
|
||||
info->free = 0;
|
||||
info->num_1block = 0;
|
||||
info->num_2block = 0;
|
||||
info->max_block = 0;
|
||||
for (machine_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
machine_uint_t kind = ATB_GET_KIND(block);
|
||||
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
mp_uint_t kind = ATB_GET_KIND(block);
|
||||
if (kind == AT_FREE || kind == AT_HEAD) {
|
||||
if (len == 1) {
|
||||
info->num_1block += 1;
|
||||
@@ -345,8 +360,8 @@ void gc_info(gc_info_t *info) {
|
||||
info->free *= BYTES_PER_BLOCK;
|
||||
}
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||
mp_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
|
||||
|
||||
// check if GC is locked
|
||||
@@ -359,15 +374,15 @@ void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
machine_uint_t i;
|
||||
machine_uint_t end_block;
|
||||
machine_uint_t start_block;
|
||||
machine_uint_t n_free = 0;
|
||||
mp_uint_t i;
|
||||
mp_uint_t end_block;
|
||||
mp_uint_t start_block;
|
||||
mp_uint_t n_free = 0;
|
||||
int collected = 0;
|
||||
for (;;) {
|
||||
|
||||
// look for a run of n_blocks available blocks
|
||||
for (i = 0; i < gc_alloc_table_byte_len; i++) {
|
||||
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
|
||||
byte a = gc_alloc_table_start[i];
|
||||
if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
|
||||
if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
|
||||
@@ -390,24 +405,34 @@ found:
|
||||
end_block = i;
|
||||
start_block = i - n_free + 1;
|
||||
|
||||
// Set last free ATB index to block after last block we found, for start of
|
||||
// next scan. To reduce fragmentation, we only do this if we were looking
|
||||
// for a single free block, which guarantees that there are no free blocks
|
||||
// before this one. Also, whenever we free or shink a block we must check
|
||||
// if this index needs adjusting (see gc_realloc and gc_free).
|
||||
if (n_free == 1) {
|
||||
gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// mark first block as used head
|
||||
ATB_FREE_TO_HEAD(start_block);
|
||||
|
||||
// mark rest of blocks as used tail
|
||||
// TODO for a run of many blocks can make this more efficient
|
||||
for (machine_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
for (mp_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// get pointer to first block
|
||||
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
|
||||
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks
|
||||
// This is needed because the blocks may have previously held pointers
|
||||
// to the heap and will not be set to something else if the caller
|
||||
// doesn't actually use the entire block. As such they will continue
|
||||
// to point to the heap and may prevent other blocks from being reclaimed.
|
||||
memset(ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
if (has_finaliser) {
|
||||
@@ -418,15 +443,19 @@ found:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
void *gc_alloc(machine_uint_t n_bytes) {
|
||||
void *gc_alloc(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
void *gc_alloc_with_finaliser(machine_uint_t n_bytes) {
|
||||
void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, true);
|
||||
}
|
||||
*/
|
||||
@@ -438,28 +467,38 @@ void gc_free(void *ptr_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
DEBUG_printf("gc_free(%p)\n", ptr);
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// set the last_free pointer to this block if it's earlier in the heap
|
||||
if (block / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = block / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// free head and all of its tail blocks
|
||||
do {
|
||||
ATB_ANY_TO_FREE(block);
|
||||
block += 1;
|
||||
} while (ATB_GET_KIND(block) == AT_TAIL);
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t gc_nbytes(void *ptr_in) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// work out number of consecutive blocks in the chain starting with this on
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
@@ -473,8 +512,8 @@ machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
|
||||
#if 0
|
||||
// old, simple realloc that didn't expand memory in place
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
machine_uint_t n_existing = gc_nbytes(ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
|
||||
mp_uint_t n_existing = gc_nbytes(ptr);
|
||||
if (n_bytes <= n_existing) {
|
||||
return ptr;
|
||||
} else {
|
||||
@@ -483,7 +522,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
has_finaliser = false;
|
||||
} else {
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr));
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
|
||||
#else
|
||||
has_finaliser = false;
|
||||
#endif
|
||||
@@ -500,7 +539,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
|
||||
#else // Alternative gc_realloc impl
|
||||
|
||||
void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
if (gc_lock_depth > 0) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -510,7 +549,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
// sanity check the ptr
|
||||
if (!VERIFY_PTR(ptr)) {
|
||||
@@ -518,7 +557,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// get first block
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
|
||||
// sanity check the ptr is pointing to the head of a block
|
||||
if (ATB_GET_KIND(block) != AT_HEAD) {
|
||||
@@ -526,14 +565,14 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// compute number of new blocks that are requested
|
||||
machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
|
||||
// get the number of consecutive tail blocks and
|
||||
// the number of free blocks after last tail block
|
||||
// stop if we reach (or are at) end of heap
|
||||
machine_uint_t n_free = 0;
|
||||
machine_uint_t n_blocks = 1; // counting HEAD block
|
||||
machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
mp_uint_t n_free = 0;
|
||||
mp_uint_t n_blocks = 1; // counting HEAD block
|
||||
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
while (block + n_blocks + n_free < max_block) {
|
||||
if (n_blocks + n_free >= new_blocks) {
|
||||
// stop as soon as we find enough blocks for n_bytes
|
||||
@@ -556,22 +595,36 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
// check if we can shrink the allocated area
|
||||
if (new_blocks < n_blocks) {
|
||||
// free unneeded tail blocks
|
||||
for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
ATB_ANY_TO_FREE(bl);
|
||||
}
|
||||
|
||||
// set the last_free pointer to end of this block if it's earlier in the heap
|
||||
if ((block + new_blocks) / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ptr_in;
|
||||
}
|
||||
|
||||
// check if we can expand in place
|
||||
if (new_blocks <= n_blocks + n_free) {
|
||||
// mark few more blocks as used tail
|
||||
for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
for (mp_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
assert(ATB_GET_KIND(bl) == AT_FREE);
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
|
||||
memset(ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
|
||||
memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ptr_in;
|
||||
}
|
||||
@@ -590,7 +643,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_printf("gc_realloc: allocating new block\n");
|
||||
DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out);
|
||||
memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
|
||||
gc_free(ptr_in);
|
||||
return ptr_out;
|
||||
@@ -606,9 +659,34 @@ void gc_dump_info() {
|
||||
}
|
||||
|
||||
void gc_dump_alloc_table(void) {
|
||||
static const mp_uint_t DUMP_BYTES_PER_LINE = 64;
|
||||
#if !EXTENSIVE_HEAP_PROFILING
|
||||
// When comparing heap output we don't want to print the starting
|
||||
// pointer of the heap because it changes from run to run.
|
||||
printf("GC memory layout; from %p:", gc_pool_start);
|
||||
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % 64 == 0) {
|
||||
#endif
|
||||
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % DUMP_BYTES_PER_LINE == 0) {
|
||||
// a new line of blocks
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
{
|
||||
// check if this line contains only free blocks
|
||||
bool only_free_blocks = true;
|
||||
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
|
||||
if (ATB_GET_KIND(bl2) != AT_FREE) {
|
||||
|
||||
only_free_blocks = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (only_free_blocks) {
|
||||
// line contains only free blocks, so skip printing it
|
||||
bl += DUMP_BYTES_PER_LINE - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// print header for new line of blocks
|
||||
printf("\n%04x: ", (uint)bl);
|
||||
}
|
||||
int c = ' ';
|
||||
@@ -617,12 +695,12 @@ void gc_dump_alloc_table(void) {
|
||||
case AT_HEAD: c = 'h'; break;
|
||||
/* this prints the uPy object type of the head block
|
||||
case AT_HEAD: {
|
||||
machine_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (machine_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
else { c = 'h'; }
|
||||
break;
|
||||
}
|
||||
@@ -637,23 +715,23 @@ void gc_dump_alloc_table(void) {
|
||||
|
||||
#if DEBUG_PRINT
|
||||
void gc_test(void) {
|
||||
machine_uint_t len = 500;
|
||||
machine_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(machine_uint_t));
|
||||
mp_uint_t len = 500;
|
||||
mp_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(mp_uint_t));
|
||||
void *ptrs[100];
|
||||
{
|
||||
machine_uint_t **p = gc_alloc(16, false);
|
||||
mp_uint_t **p = gc_alloc(16, false);
|
||||
p[0] = gc_alloc(64, false);
|
||||
p[1] = gc_alloc(1, false);
|
||||
p[2] = gc_alloc(1, false);
|
||||
p[3] = gc_alloc(1, false);
|
||||
machine_uint_t ***p2 = gc_alloc(16, false);
|
||||
mp_uint_t ***p2 = gc_alloc(16, false);
|
||||
p2[0] = p;
|
||||
p2[1] = p;
|
||||
ptrs[0] = p2;
|
||||
}
|
||||
for (int i = 0; i < 25; i+=2) {
|
||||
machine_uint_t *p = gc_alloc(i, false);
|
||||
mp_uint_t *p = gc_alloc(i, false);
|
||||
printf("p=%p\n", p);
|
||||
if (i & 3) {
|
||||
//ptrs[i] = p;
|
||||
|
||||
21
py/gc.h
21
py/gc.h
@@ -30,25 +30,26 @@ void gc_init(void *start, void *end);
|
||||
// They can be used to prevent the GC from allocating/freeing.
|
||||
void gc_lock(void);
|
||||
void gc_unlock(void);
|
||||
bool gc_is_locked(void);
|
||||
|
||||
// A given port must implement gc_collect by using the other collect functions.
|
||||
void gc_collect(void);
|
||||
void gc_collect_start(void);
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len);
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len);
|
||||
void gc_collect_end(void);
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser);
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
|
||||
void gc_free(void *ptr);
|
||||
machine_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes);
|
||||
mp_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
|
||||
|
||||
typedef struct _gc_info_t {
|
||||
machine_uint_t total;
|
||||
machine_uint_t used;
|
||||
machine_uint_t free;
|
||||
machine_uint_t num_1block;
|
||||
machine_uint_t num_2block;
|
||||
machine_uint_t max_block;
|
||||
mp_uint_t total;
|
||||
mp_uint_t used;
|
||||
mp_uint_t free;
|
||||
mp_uint_t num_1block;
|
||||
mp_uint_t num_2block;
|
||||
mp_uint_t max_block;
|
||||
} gc_info_t;
|
||||
|
||||
void gc_info(gc_info_t *info);
|
||||
|
||||
132
py/lexer.c
132
py/lexer.c
@@ -32,8 +32,8 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
@@ -45,30 +45,30 @@
|
||||
struct _mp_lexer_t {
|
||||
qstr source_name; // name of source
|
||||
void *stream_data; // data for stream
|
||||
mp_lexer_stream_next_char_t stream_next_char; // stream callback to get next char
|
||||
mp_lexer_stream_next_byte_t stream_next_byte; // stream callback to get next byte
|
||||
mp_lexer_stream_close_t stream_close; // stream callback to free
|
||||
|
||||
unichar chr0, chr1, chr2; // current cached characters from source
|
||||
|
||||
uint line; // source line
|
||||
uint column; // source column
|
||||
mp_uint_t line; // source line
|
||||
mp_uint_t column; // source column
|
||||
|
||||
int emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
int nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
|
||||
uint alloc_indent_level;
|
||||
uint num_indent_level;
|
||||
mp_uint_t alloc_indent_level;
|
||||
mp_uint_t num_indent_level;
|
||||
uint16_t *indent_level;
|
||||
|
||||
vstr_t vstr;
|
||||
mp_token_t tok_cur;
|
||||
};
|
||||
|
||||
uint mp_optimise_value;
|
||||
mp_uint_t mp_optimise_value;
|
||||
|
||||
// TODO replace with a call to a standard function
|
||||
bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
uint i = 0;
|
||||
bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
|
||||
mp_uint_t i = 0;
|
||||
|
||||
while (i < len && *str == *strn) {
|
||||
++i;
|
||||
@@ -81,10 +81,10 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
|
||||
#ifdef MICROPY_DEBUG_PRINTERS
|
||||
void mp_token_show(const mp_token_t *tok) {
|
||||
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:" UINT_FMT, tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
if (tok->str != NULL && tok->len > 0) {
|
||||
const char *i = tok->str;
|
||||
const char *j = i + tok->len;
|
||||
const byte *i = (const byte *)tok->str;
|
||||
const byte *j = (const byte *)i + tok->len;
|
||||
printf(" ");
|
||||
while (i < j) {
|
||||
unichar c = utf8_get_char(i);
|
||||
@@ -103,7 +103,7 @@ void mp_token_show(const mp_token_t *tok) {
|
||||
#define CUR_CHAR(lex) ((lex)->chr0)
|
||||
|
||||
STATIC bool is_end(mp_lexer_t *lex) {
|
||||
return lex->chr0 == MP_LEXER_CHAR_EOF;
|
||||
return lex->chr0 == MP_LEXER_EOF;
|
||||
}
|
||||
|
||||
STATIC bool is_physical_newline(mp_lexer_t *lex) {
|
||||
@@ -171,11 +171,11 @@ STATIC bool is_tail_of_identifier(mp_lexer_t *lex) {
|
||||
}
|
||||
|
||||
STATIC void next_char(mp_lexer_t *lex) {
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
int advance = 1;
|
||||
mp_uint_t advance = 1;
|
||||
|
||||
if (lex->chr0 == '\n') {
|
||||
// LF is a new line
|
||||
@@ -200,17 +200,17 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
for (; advance > 0; advance--) {
|
||||
lex->chr0 = lex->chr1;
|
||||
lex->chr1 = lex->chr2;
|
||||
lex->chr2 = lex->stream_next_char(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
lex->chr2 = lex->stream_next_byte(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_EOF) {
|
||||
// EOF
|
||||
if (lex->chr1 != MP_LEXER_CHAR_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
if (lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n'; // insert newline at end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void indent_push(mp_lexer_t *lex, uint indent) {
|
||||
void indent_push(mp_lexer_t *lex, mp_uint_t indent) {
|
||||
if (lex->num_indent_level >= lex->alloc_indent_level) {
|
||||
// TODO use m_renew_maybe and somehow indicate an error if it fails... probably by using MP_TOKEN_MEMORY_ERROR
|
||||
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);
|
||||
@@ -219,7 +219,7 @@ void indent_push(mp_lexer_t *lex, uint indent) {
|
||||
lex->indent_level[lex->num_indent_level++] = indent;
|
||||
}
|
||||
|
||||
uint indent_top(mp_lexer_t *lex) {
|
||||
mp_uint_t indent_top(mp_lexer_t *lex) {
|
||||
return lex->indent_level[lex->num_indent_level - 1];
|
||||
}
|
||||
|
||||
@@ -308,9 +308,9 @@ STATIC const char *tok_kw[] = {
|
||||
"__debug__",
|
||||
};
|
||||
|
||||
STATIC int hex_digit(unichar c) {
|
||||
STATIC mp_uint_t hex_digit(unichar c) {
|
||||
// c is assumed to be hex digit
|
||||
int n = c - '0';
|
||||
mp_uint_t n = c - '0';
|
||||
if (n > 9) {
|
||||
n &= ~('a' - 'A');
|
||||
n -= ('A' - ('9' + 1));
|
||||
@@ -320,8 +320,9 @@ STATIC int hex_digit(unichar c) {
|
||||
|
||||
// This is called with CUR_CHAR() before first hex digit, and should return with
|
||||
// it pointing to last hex digit
|
||||
STATIC bool get_hex(mp_lexer_t *lex, int num_digits, uint *result) {
|
||||
uint num = 0;
|
||||
// num_digits must be greater than zero
|
||||
STATIC bool get_hex(mp_lexer_t *lex, mp_uint_t num_digits, mp_uint_t *result) {
|
||||
mp_uint_t num = 0;
|
||||
while (num_digits-- != 0) {
|
||||
next_char(lex);
|
||||
unichar c = CUR_CHAR(lex);
|
||||
@@ -394,7 +395,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
} else if (had_physical_newline && lex->nested_bracket_level == 0) {
|
||||
tok->kind = MP_TOKEN_NEWLINE;
|
||||
|
||||
uint num_spaces = lex->column - 1;
|
||||
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)) {
|
||||
@@ -463,7 +464,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
next_char(lex);
|
||||
|
||||
// work out if it's a single or triple quoted literal
|
||||
int num_quotes;
|
||||
mp_uint_t num_quotes;
|
||||
if (is_char_and(lex, quote_char, quote_char)) {
|
||||
// triple quotes
|
||||
next_char(lex);
|
||||
@@ -475,7 +476,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
}
|
||||
|
||||
// parse the literal
|
||||
int n_closing = 0;
|
||||
mp_uint_t n_closing = 0;
|
||||
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
|
||||
if (is_char(lex, quote_char)) {
|
||||
n_closing += 1;
|
||||
@@ -490,8 +491,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
} else {
|
||||
switch (c) {
|
||||
case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case MP_LEXER_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case '\\': break;
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
@@ -502,24 +503,37 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
case 'v': c = 0x0b; break;
|
||||
case 'f': c = 0x0c; break;
|
||||
case 'r': c = 0x0d; break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (is_bytes) {
|
||||
// b'\u1234' == b'\\u1234'
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through.
|
||||
case 'x':
|
||||
{
|
||||
uint num = 0;
|
||||
if (!get_hex(lex, 2, &num)) {
|
||||
mp_uint_t num = 0;
|
||||
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
|
||||
// TODO error message
|
||||
assert(0);
|
||||
}
|
||||
c = num;
|
||||
break;
|
||||
}
|
||||
case 'N': break; // TODO \N{name} only in strings
|
||||
case 'u': break; // TODO \uxxxx only in strings
|
||||
case 'U': break; // TODO \Uxxxxxxxx only in strings
|
||||
case 'N':
|
||||
// Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the
|
||||
// entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly
|
||||
// 3MB of text; even gzip-compressed and with minimal structure, it'll take
|
||||
// roughly half a meg of storage. This form of Unicode escape may be added
|
||||
// later on, but it's definitely not a priority right now. -- CJA 20140607
|
||||
assert(!"Unicode name escapes not supported");
|
||||
break;
|
||||
default:
|
||||
if (c >= '0' && c <= '7') {
|
||||
// Octal sequence, 1-3 chars
|
||||
int digits = 3;
|
||||
int num = c - '0';
|
||||
mp_uint_t digits = 3;
|
||||
mp_uint_t num = c - '0';
|
||||
while (is_following_odigit(lex) && --digits != 0) {
|
||||
next_char(lex);
|
||||
num = num * 8 + (CUR_CHAR(lex) - '0');
|
||||
@@ -532,11 +546,19 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c != MP_LEXER_CHAR_EOF) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
if (c != MP_LEXER_EOF) {
|
||||
if (c < 0x110000 && !is_bytes) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
} else if (c < 0x100 && is_bytes) {
|
||||
vstr_add_byte(&lex->vstr, c);
|
||||
} else {
|
||||
assert(!"TODO: Throw an error, invalid escape code probably");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
|
||||
// Add the "character" as a byte so that we remain 8-bit clean.
|
||||
// This way, strings are parsed correctly whether or not they contain utf-8 chars.
|
||||
vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
|
||||
}
|
||||
}
|
||||
next_char(lex);
|
||||
@@ -608,7 +630,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
// search for encoded delimiter or operator
|
||||
|
||||
const char *t = tok_enc;
|
||||
uint tok_enc_index = 0;
|
||||
mp_uint_t tok_enc_index = 0;
|
||||
for (; *t != 0 && !is_char(lex, *t); t += 1) {
|
||||
if (*t == 'e' || *t == 'c') {
|
||||
t += 1;
|
||||
@@ -630,7 +652,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
|
||||
// get the maximum characters for a valid token
|
||||
t += 1;
|
||||
uint t_index = tok_enc_index;
|
||||
mp_uint_t t_index = tok_enc_index;
|
||||
for (;;) {
|
||||
for (; *t == 'e'; t += 1) {
|
||||
t += 1;
|
||||
@@ -693,11 +715,11 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
// the parser gives a syntax error on, eg, x.__debug__. Otherwise, we
|
||||
// need to check for this special token in many places in the compiler.
|
||||
// TODO improve speed of these string comparisons
|
||||
//for (int i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (int i = 0; i < ARRAY_SIZE(tok_kw); i++) {
|
||||
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
|
||||
if (str_strn_equal(tok_kw[i], tok->str, tok->len)) {
|
||||
if (i == ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[ARRAY_SIZE(tok_kw) - 1] == "__debug__"
|
||||
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__"
|
||||
tok->kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
|
||||
} else {
|
||||
tok->kind = MP_TOKEN_KW_FALSE + i;
|
||||
@@ -708,7 +730,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
}
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *lex = m_new_maybe(mp_lexer_t, 1);
|
||||
|
||||
// check for memory allocation error
|
||||
@@ -721,7 +743,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
|
||||
|
||||
lex->source_name = src_name;
|
||||
lex->stream_data = stream_data;
|
||||
lex->stream_next_char = stream_next_char;
|
||||
lex->stream_next_byte = stream_next_byte;
|
||||
lex->stream_close = stream_close;
|
||||
lex->line = 1;
|
||||
lex->column = 1;
|
||||
@@ -742,18 +764,18 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
|
||||
lex->indent_level[0] = 0;
|
||||
|
||||
// preload characters
|
||||
lex->chr0 = stream_next_char(stream_data);
|
||||
lex->chr1 = stream_next_char(stream_data);
|
||||
lex->chr2 = stream_next_char(stream_data);
|
||||
lex->chr0 = stream_next_byte(stream_data);
|
||||
lex->chr1 = stream_next_byte(stream_data);
|
||||
lex->chr2 = stream_next_byte(stream_data);
|
||||
|
||||
// if input stream is 0, 1 or 2 characters long and doesn't end in a newline, then insert a newline at the end
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
lex->chr0 = '\n';
|
||||
} else if (lex->chr1 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr1 == MP_LEXER_EOF) {
|
||||
if (lex->chr0 != '\n' && lex->chr0 != '\r') {
|
||||
lex->chr1 = '\n';
|
||||
}
|
||||
} else if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr2 == MP_LEXER_EOF) {
|
||||
if (lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n';
|
||||
}
|
||||
|
||||
22
py/lexer.h
22
py/lexer.h
@@ -131,27 +131,27 @@ typedef enum _mp_token_kind_t {
|
||||
} mp_token_kind_t;
|
||||
|
||||
typedef struct _mp_token_t {
|
||||
uint src_line; // source line
|
||||
uint src_column; // source column
|
||||
mp_uint_t src_line; // source line
|
||||
mp_uint_t src_column; // source column
|
||||
|
||||
mp_token_kind_t kind; // kind of token
|
||||
const char *str; // string of token (valid only while this token is current token)
|
||||
uint len; // (byte) length of string of token
|
||||
mp_uint_t len; // (byte) length of string of token
|
||||
} mp_token_t;
|
||||
|
||||
// the next-char function must return the next character in the stream
|
||||
// it must return MP_LEXER_CHAR_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_CHAR_EOF, and in that case must return MP_LEXER_CHAR_EOF
|
||||
#define MP_LEXER_CHAR_EOF (-1)
|
||||
typedef unichar (*mp_lexer_stream_next_char_t)(void*);
|
||||
// the next-byte function must return the next byte in the stream
|
||||
// it must return MP_LEXER_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_EOF, and in that case must return MP_LEXER_EOF
|
||||
#define MP_LEXER_EOF (-1)
|
||||
typedef mp_uint_t (*mp_lexer_stream_next_byte_t)(void*);
|
||||
typedef void (*mp_lexer_stream_close_t)(void*);
|
||||
|
||||
typedef struct _mp_lexer_t mp_lexer_t;
|
||||
|
||||
void mp_token_show(const mp_token_t *tok);
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len);
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
|
||||
|
||||
void mp_lexer_free(mp_lexer_t *lex);
|
||||
qstr mp_lexer_source_name(mp_lexer_t *lex);
|
||||
@@ -177,4 +177,4 @@ typedef enum {
|
||||
mp_import_stat_t mp_import_stat(const char *path);
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
|
||||
extern uint mp_optimise_value;
|
||||
extern mp_uint_t mp_optimise_value;
|
||||
|
||||
@@ -24,23 +24,23 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct _mp_lexer_str_buf_t {
|
||||
uint free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
const char *src_beg; // beginning of source
|
||||
const char *src_cur; // current location in source
|
||||
const char *src_end; // end (exclusive) of source
|
||||
} mp_lexer_str_buf_t;
|
||||
|
||||
STATIC unichar str_buf_next_char(mp_lexer_str_buf_t *sb) {
|
||||
STATIC mp_uint_t str_buf_next_byte(mp_lexer_str_buf_t *sb) {
|
||||
if (sb->src_cur < sb->src_end) {
|
||||
return *sb->src_cur++;
|
||||
} else {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ STATIC void str_buf_free(mp_lexer_str_buf_t *sb) {
|
||||
m_del_obj(mp_lexer_str_buf_t, sb);
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len) {
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) {
|
||||
mp_lexer_str_buf_t *sb = m_new_obj(mp_lexer_str_buf_t);
|
||||
sb->free_len = free_len;
|
||||
sb->src_beg = str;
|
||||
sb->src_cur = str;
|
||||
sb->src_end = str + len;
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_char_t)str_buf_next_char, (mp_lexer_stream_close_t)str_buf_free);
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str_buf_next_byte, (mp_lexer_stream_close_t)str_buf_free);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -41,20 +41,20 @@
|
||||
|
||||
typedef struct _mp_lexer_file_buf_t {
|
||||
int fd;
|
||||
char buf[20];
|
||||
uint len;
|
||||
uint pos;
|
||||
byte buf[20];
|
||||
mp_uint_t len;
|
||||
mp_uint_t pos;
|
||||
} mp_lexer_file_buf_t;
|
||||
|
||||
STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
|
||||
STATIC mp_uint_t file_buf_next_byte(mp_lexer_file_buf_t *fb) {
|
||||
if (fb->pos >= fb->len) {
|
||||
if (fb->len == 0) {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
} else {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
if (n <= 0) {
|
||||
fb->len = 0;
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
@@ -78,7 +78,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_byte_t)file_buf_next_byte, (mp_lexer_stream_close_t)file_buf_close);
|
||||
}
|
||||
|
||||
#endif // MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
|
||||
6
py/map.c
6
py/map.c
@@ -27,8 +27,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -167,7 +167,7 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % map->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_map_elem_t *avail_slot = NULL;
|
||||
@@ -270,7 +270,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % set->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_obj_t *avail_slot = NULL;
|
||||
|
||||
26
py/misc.h
26
py/misc.h
@@ -82,14 +82,17 @@ int m_get_peak_bytes_allocated(void);
|
||||
/** array helpers ***********************************************/
|
||||
|
||||
// get the number of elements in a fixed-size array
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
// align ptr to the nearest multiple of "alignment"
|
||||
#define MP_ALIGN(ptr, alignment) (void*)(((mp_uint_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||
|
||||
/** unichar / UTF-8 *********************************************/
|
||||
|
||||
typedef int unichar; // TODO
|
||||
|
||||
unichar utf8_get_char(const char *s);
|
||||
char *utf8_next_char(const char *s);
|
||||
unichar utf8_get_char(const byte *s);
|
||||
const byte *utf8_next_char(const byte *s);
|
||||
|
||||
bool unichar_isspace(unichar c);
|
||||
bool unichar_isalpha(unichar c);
|
||||
@@ -100,6 +103,9 @@ bool unichar_isupper(unichar c);
|
||||
bool unichar_islower(unichar c);
|
||||
unichar unichar_tolower(unichar c);
|
||||
unichar unichar_toupper(unichar c);
|
||||
mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
|
||||
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
|
||||
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
|
||||
|
||||
/** variable string *********************************************/
|
||||
|
||||
@@ -163,4 +169,18 @@ int DEBUG_printf(const char *fmt, ...);
|
||||
|
||||
extern uint mp_verbose_flag;
|
||||
|
||||
// This is useful for unicode handling. Some CPU archs has
|
||||
// special instructions for efficient implentation of this
|
||||
// function (e.g. CLZ on ARM).
|
||||
// NOTE: this function is unused at the moment
|
||||
#ifndef count_lead_ones
|
||||
static inline uint count_lead_ones(byte val) {
|
||||
uint c = 0;
|
||||
for (byte mask = 0x80; val & mask; mask >>= 1) {
|
||||
c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDED_MINILIB_H
|
||||
|
||||
@@ -73,9 +73,9 @@ all: $(PROG)
|
||||
|
||||
$(PROG): $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
$(Q)$(CC) $(COPT) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
ifndef DEBUG
|
||||
$(Q)$(STRIP) $(PROG)
|
||||
$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
|
||||
endif
|
||||
$(Q)$(SIZE) $(PROG)
|
||||
|
||||
@@ -97,4 +97,10 @@ print-cfg:
|
||||
$(ECHO) "OBJ = $(OBJ)"
|
||||
.PHONY: print-cfg
|
||||
|
||||
print-def:
|
||||
@$(ECHO) "The following defines are built into the $(CC) compiler"
|
||||
touch __empty__.c
|
||||
@$(CC) -E -Wp,-dM __empty__.c
|
||||
@$(RM) -f __empty__.c
|
||||
|
||||
-include $(OBJ:.o=.P)
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_array_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array },
|
||||
@@ -40,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_array_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_array_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -51,3 +53,5 @@ const mp_obj_module_t mp_module_array = {
|
||||
.name = MP_QSTR_array,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_array_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,18 +26,27 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
/// \module cmath - mathematical functions for complex numbers
|
||||
///
|
||||
/// The `cmath` module provides some basic mathematical funtions for
|
||||
/// working with complex numbers.
|
||||
|
||||
// These are defined in modmath.c
|
||||
/// \constant e - base of the natural logarithm
|
||||
extern const mp_obj_float_t mp_math_e_obj;
|
||||
/// \constant pi - the ratio of a circle's circumference to its diameter
|
||||
extern const mp_obj_float_t mp_math_pi_obj;
|
||||
|
||||
/// \function phase(z)
|
||||
/// Returns the phase of the number `z`, in the range (-pi, +pi].
|
||||
mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -45,6 +54,8 @@ mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);
|
||||
|
||||
/// \function polar(z)
|
||||
/// Returns, as a tuple, the polar form of `z`.
|
||||
mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -56,6 +67,8 @@ mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar);
|
||||
|
||||
/// \function rect(r, phi)
|
||||
/// Returns the complex number with modulus `r` and phase `phi`.
|
||||
mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
mp_float_t r = mp_obj_get_float(r_obj);
|
||||
mp_float_t phi = mp_obj_get_float(phi_obj);
|
||||
@@ -63,6 +76,8 @@ mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect);
|
||||
|
||||
/// \function exp(z)
|
||||
/// Return the exponential of `z`.
|
||||
mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -71,6 +86,8 @@ mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
|
||||
|
||||
/// \function log(z)
|
||||
/// Return the natural logarithm of `z`. The branch cut is along the negative real axis.
|
||||
// TODO can take second argument, being the base
|
||||
mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
@@ -79,6 +96,8 @@ mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
|
||||
|
||||
/// \function log10(z)
|
||||
/// Return the base-10 logarithm of `z`. The branch cut is along the negative real axis.
|
||||
mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -86,6 +105,8 @@ mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
|
||||
|
||||
/// \function sqrt(z)
|
||||
/// Return the square-root of `z`.
|
||||
mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -95,6 +116,8 @@ mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
|
||||
|
||||
/// \function cos(z)
|
||||
/// Return the cosine of `z`.
|
||||
mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -102,6 +125,8 @@ mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos);
|
||||
|
||||
/// \function sin(z)
|
||||
/// Return the sine of `z`.
|
||||
mp_obj_t mp_cmath_sin(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -142,8 +167,8 @@ STATIC const mp_obj_dict_t mp_module_cmath_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_cmath_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -42,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_collections_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_collections_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
36
py/modgc.c
36
py/modgc.c
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -37,35 +37,63 @@
|
||||
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
|
||||
/// \module gc - control the garbage collector
|
||||
|
||||
extern uint gc_collected;
|
||||
|
||||
/// \function collect()
|
||||
/// Run a garbage collection.
|
||||
STATIC mp_obj_t py_gc_collect(void) {
|
||||
gc_collect();
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_uint_t)gc_collected);
|
||||
return MP_OBJ_NEW_SMALL_INT(gc_collected);
|
||||
#else
|
||||
return mp_const_none;
|
||||
#endif
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
|
||||
/// \function disable()
|
||||
/// Disable the garbage collector.
|
||||
STATIC mp_obj_t gc_disable(void) {
|
||||
gc_lock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||
|
||||
/// \function enable()
|
||||
/// Enable the garbage collector.
|
||||
STATIC mp_obj_t gc_enable(void) {
|
||||
gc_unlock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||
|
||||
/// \function mem_free()
|
||||
/// Return the number of bytes of available heap RAM.
|
||||
STATIC mp_obj_t gc_mem_free(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.free);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);
|
||||
|
||||
/// \function mem_alloc()
|
||||
/// Return the number of bytes of heap RAM that are allocated.
|
||||
STATIC mp_obj_t gc_mem_alloc(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.used);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gc) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
@@ -73,8 +101,8 @@ STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_gc_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -57,8 +57,8 @@ STATIC const mp_obj_dict_t mp_module_io_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_io_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_io_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
62
py/modmath.c
62
py/modmath.c
@@ -26,14 +26,19 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
|
||||
|
||||
/// \module math - mathematical functions
|
||||
///
|
||||
/// The `math` module provides some basic mathematical funtions for
|
||||
/// working with floating-point numbers.
|
||||
|
||||
//TODO: Change macros to check for overflow and raise OverflowError or RangeError
|
||||
#define MATH_FUN_1(py_name, c_name) \
|
||||
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
|
||||
@@ -48,50 +53,95 @@
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
|
||||
|
||||
#define MATH_FUN_1_TO_INT(py_name, c_name) \
|
||||
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((machine_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
|
||||
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((mp_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
|
||||
|
||||
// These are also used by cmath.c
|
||||
/// \constant e - base of the natural logarithm
|
||||
const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E};
|
||||
/// \constant pi - the ratio of a circle's circumference to its diameter
|
||||
const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI};
|
||||
|
||||
/// \function sqrt(x)
|
||||
/// Returns the square root of `x`.
|
||||
MATH_FUN_1(sqrt, sqrt)
|
||||
/// \function pow(x, y)
|
||||
/// Returns `x` to the power of `y`.
|
||||
MATH_FUN_2(pow, pow)
|
||||
/// \function exp(x)
|
||||
MATH_FUN_1(exp, exp)
|
||||
/// \function expm1(x)
|
||||
MATH_FUN_1(expm1, expm1)
|
||||
/// \function log(x)
|
||||
MATH_FUN_1(log, log)
|
||||
/// \function log2(x)
|
||||
MATH_FUN_1(log2, log2)
|
||||
/// \function log10(x)
|
||||
MATH_FUN_1(log10, log10)
|
||||
/// \function cosh(x)
|
||||
MATH_FUN_1(cosh, cosh)
|
||||
/// \function sinh(x)
|
||||
MATH_FUN_1(sinh, sinh)
|
||||
/// \function tanh(x)
|
||||
MATH_FUN_1(tanh, tanh)
|
||||
/// \function acosh(x)
|
||||
MATH_FUN_1(acosh, acosh)
|
||||
/// \function asinh(x)
|
||||
MATH_FUN_1(asinh, asinh)
|
||||
/// \function atanh(x)
|
||||
MATH_FUN_1(atanh, atanh)
|
||||
/// \function cos(x)
|
||||
MATH_FUN_1(cos, cos)
|
||||
/// \function sin(x)
|
||||
MATH_FUN_1(sin, sin)
|
||||
/// \function tan(x)
|
||||
MATH_FUN_1(tan, tan)
|
||||
/// \function acos(x)
|
||||
MATH_FUN_1(acos, acos)
|
||||
/// \function asin(x)
|
||||
MATH_FUN_1(asin, asin)
|
||||
/// \function atan(x)
|
||||
MATH_FUN_1(atan, atan)
|
||||
/// \function atan2(y, x)
|
||||
MATH_FUN_2(atan2, atan2)
|
||||
/// \function ceil(x)
|
||||
MATH_FUN_1_TO_INT(ceil, ceil)
|
||||
/// \function copysign(x, y)
|
||||
MATH_FUN_2(copysign, copysign)
|
||||
/// \function fabs(x)
|
||||
MATH_FUN_1(fabs, fabs)
|
||||
/// \function floor(x)
|
||||
MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
|
||||
/// \function fmod(x, y)
|
||||
MATH_FUN_2(fmod, fmod)
|
||||
/// \function isfinite(x)
|
||||
MATH_FUN_1_TO_BOOL(isfinite, isfinite)
|
||||
/// \function isinf(x)
|
||||
MATH_FUN_1_TO_BOOL(isinf, isinf)
|
||||
/// \function isnan(x)
|
||||
MATH_FUN_1_TO_BOOL(isnan, isnan)
|
||||
/// \function trunc(x)
|
||||
MATH_FUN_1_TO_INT(trunc, trunc)
|
||||
/// \function ldexp(x, exp)
|
||||
MATH_FUN_2(ldexp, ldexp)
|
||||
/// \function erf(x)
|
||||
/// Return the error function of `x`.
|
||||
MATH_FUN_1(erf, erf)
|
||||
/// \function erfc(x)
|
||||
/// Return the complementary error function of `x`.
|
||||
MATH_FUN_1(erfc, erfc)
|
||||
/// \function gamma(x)
|
||||
/// Return the gamma function of `x`.
|
||||
MATH_FUN_1(gamma, tgamma)
|
||||
/// \function lgamma(x)
|
||||
/// return the natural logarithm of the gamma function of `x`.
|
||||
MATH_FUN_1(lgamma, lgamma)
|
||||
//TODO: factorial, fsum
|
||||
|
||||
// Functions that return a tuple
|
||||
|
||||
/// \function frexp(x)
|
||||
/// Converts a floating-point number to fractional and integral components.
|
||||
mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
|
||||
int int_exponent = 0;
|
||||
mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
|
||||
@@ -102,6 +152,7 @@ mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
|
||||
|
||||
/// \function modf(x)
|
||||
mp_obj_t mp_math_modf(mp_obj_t x_obj) {
|
||||
mp_float_t int_part = 0.0;
|
||||
mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
|
||||
@@ -113,11 +164,14 @@ mp_obj_t mp_math_modf(mp_obj_t x_obj) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
|
||||
|
||||
// Angular conversions
|
||||
|
||||
/// \function radians(x)
|
||||
mp_obj_t mp_math_radians(mp_obj_t x_obj) {
|
||||
return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
|
||||
|
||||
/// \function degrees(x)
|
||||
mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
|
||||
return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI);
|
||||
}
|
||||
@@ -172,8 +226,8 @@ STATIC const mp_obj_dict_t mp_module_math_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_math_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_math_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -35,15 +35,15 @@
|
||||
|
||||
#if MICROPY_MEM_STATS
|
||||
STATIC mp_obj_t mp_micropython_mem_total() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_total_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_current() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_current_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_peak() {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_peak_bytes_allocated());
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
|
||||
@@ -51,6 +51,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
|
||||
#if MICROPY_MEM_STATS
|
||||
@@ -58,6 +62,9 @@ STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alloc_emergency_exception_buf), (mp_obj_t)&mp_alloc_emergency_exception_buf_obj },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_micropython_globals = {
|
||||
@@ -65,8 +72,8 @@ STATIC const mp_obj_dict_t mp_module_micropython_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_micropython_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -74,13 +74,13 @@ STATIC char get_fmt_type(const char **fmt) {
|
||||
return t;
|
||||
}
|
||||
|
||||
STATIC machine_uint_t get_fmt_num(const char **p) {
|
||||
STATIC mp_uint_t get_fmt_num(const char **p) {
|
||||
const char *num = *p;
|
||||
uint len = 1;
|
||||
while (unichar_isdigit(*++num)) {
|
||||
len++;
|
||||
}
|
||||
machine_uint_t val = (machine_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10));
|
||||
mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10));
|
||||
*p = num;
|
||||
return val;
|
||||
}
|
||||
@@ -99,10 +99,10 @@ STATIC uint calcsize_items(const char *fmt) {
|
||||
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
|
||||
const char *fmt = mp_obj_str_get_str(fmt_in);
|
||||
char fmt_type = get_fmt_type(&fmt);
|
||||
machine_uint_t size;
|
||||
mp_uint_t size;
|
||||
for (size = 0; *fmt; fmt++) {
|
||||
uint align = 1;
|
||||
machine_uint_t cnt = 1;
|
||||
mp_uint_t cnt = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
cnt = get_fmt_num(&fmt);
|
||||
}
|
||||
@@ -111,14 +111,14 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
|
||||
assert(*fmt == 's');
|
||||
}
|
||||
|
||||
machine_uint_t sz;
|
||||
mp_uint_t sz;
|
||||
if (*fmt == 's') {
|
||||
sz = cnt;
|
||||
} else {
|
||||
sz = (machine_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
sz = (mp_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
|
||||
}
|
||||
// TODO
|
||||
assert(sz != (machine_uint_t)-1);
|
||||
assert(sz != (mp_uint_t)-1);
|
||||
// Apply alignment
|
||||
size = (size + align - 1) & ~(align - 1);
|
||||
size += sz;
|
||||
@@ -138,7 +138,7 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
|
||||
byte *p = bufinfo.buf;
|
||||
|
||||
for (uint i = 0; i < size; i++) {
|
||||
machine_uint_t sz = 1;
|
||||
mp_uint_t sz = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
sz = get_fmt_num(&fmt);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
|
||||
memset(p, 0, size);
|
||||
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
machine_uint_t sz = 1;
|
||||
mp_uint_t sz = 1;
|
||||
if (unichar_isdigit(*fmt)) {
|
||||
sz = get_fmt_num(&fmt);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
|
||||
if (*fmt == 's') {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ);
|
||||
machine_uint_t to_copy = sz;
|
||||
mp_uint_t to_copy = sz;
|
||||
if (bufinfo.len < to_copy) {
|
||||
to_copy = bufinfo.len;
|
||||
}
|
||||
@@ -210,8 +210,8 @@ STATIC const mp_obj_dict_t mp_module_struct_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_struct_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_struct_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
43
py/modsys.c
43
py/modsys.c
@@ -24,8 +24,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -33,25 +35,37 @@
|
||||
#include "objlist.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
|
||||
#if MICROPY_PY_SYS
|
||||
|
||||
/// \module sys - system specific functions
|
||||
|
||||
// These should be implemented by ports, specific types don't matter,
|
||||
// only addresses.
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_exit_obj;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
extern mp_obj_int_t mp_maxsize_obj;
|
||||
|
||||
// TODO document these properly, they aren't constants or functions...
|
||||
/// \constant path - a mutable list of directories to search for imported modules
|
||||
mp_obj_list_t mp_sys_path_obj;
|
||||
/// \constant argv - a mutable list of arguments this program started with
|
||||
mp_obj_list_t mp_sys_argv_obj;
|
||||
|
||||
/// \constant version - Python language version that this implementation conforms to, as a string
|
||||
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
|
||||
|
||||
/// \constant version_info - Python language version that this implementation conforms to, as a tuple of ints
|
||||
#define I(n) MP_OBJ_NEW_SMALL_INT(n)
|
||||
// TODO: CPython is now at 5-element array, but save 2 els so far...
|
||||
STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}};
|
||||
#undef I
|
||||
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
|
||||
|
||||
#ifdef MICROPY_PY_SYS_PLATFORM
|
||||
/// \constant platform - the platform that Micro Python is running on
|
||||
STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
|
||||
#endif
|
||||
|
||||
@@ -65,17 +79,32 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
|
||||
#ifdef MICROPY_PY_SYS_PLATFORM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_platform), (mp_obj_t)&platform_obj },
|
||||
#endif
|
||||
/// \constant byteorder - the byte order of the system ("little" or "big")
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_little) },
|
||||
#else
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_big) },
|
||||
#endif
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
||||
// INT_MAX is not representable as small int, as we know that small int
|
||||
// takes one bit for tag. So, we have little choice but to provide this
|
||||
// value. Apps also should be careful to not try to compare sys.maxsize
|
||||
// with some number (which may not fit in available int size), but instead
|
||||
// count number of significant bits in sys.maxsize.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), MP_OBJ_NEW_SMALL_INT(INT_MAX >> 1) },
|
||||
#else
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), (mp_obj_t)&mp_maxsize_obj },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_EXIT
|
||||
// documented per-port
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_exit), (mp_obj_t)&mp_sys_exit_obj },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_STDFILES
|
||||
// documented per-port
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdin), (mp_obj_t)&mp_sys_stdin_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },
|
||||
@@ -87,8 +116,8 @@ STATIC const mp_obj_dict_t mp_module_sys_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_sys_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_sys_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -111,6 +111,14 @@
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#endif
|
||||
|
||||
// Whether to emit ARM native code
|
||||
#ifndef MICROPY_EMIT_ARM
|
||||
#define MICROPY_EMIT_ARM (0)
|
||||
#endif
|
||||
|
||||
// Convenience definition for whether any native emitter is enabled
|
||||
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Compiler configuration */
|
||||
|
||||
@@ -157,6 +165,22 @@
|
||||
#define MICROPY_ENABLE_GC_FINALISER (0)
|
||||
#endif
|
||||
|
||||
// Whether to check C stack usage. C stack used for calling Python functions,
|
||||
// etc. Not checking means segfault on overflow.
|
||||
#ifndef MICROPY_STACK_CHECK
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#endif
|
||||
|
||||
// Whether to have an emergency exception buffer
|
||||
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
||||
#endif
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
# define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Whether to include REPL helper function
|
||||
#ifndef MICROPY_HELPER_REPL
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
@@ -223,6 +247,10 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_BUILTINS_FLOAT (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_BUILTINS_COMPLEX
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT)
|
||||
#endif
|
||||
|
||||
// Enable features which improve CPython compatibility
|
||||
// but may lead to more code size/memory usage.
|
||||
// TODO: Originally intended as generic category to not
|
||||
@@ -239,6 +267,16 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python builtins, classes, modules, etc */
|
||||
|
||||
// Whether str object is proper unicode
|
||||
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
|
||||
#endif
|
||||
|
||||
// Whether to support bytearray object
|
||||
#ifndef MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#endif
|
||||
|
||||
// Whether to support set object
|
||||
#ifndef MICROPY_PY_BUILTINS_SET
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
@@ -259,6 +297,18 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#endif
|
||||
|
||||
// Whether to set __file__ for imported modules
|
||||
#ifndef MICROPY_PY___FILE__
|
||||
#define MICROPY_PY___FILE__ (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "array" module. Note that large chunk of the
|
||||
// underlying code is shared with "bytearray" builtin type, so to
|
||||
// get real savings, it should be disabled too.
|
||||
#ifndef MICROPY_PY_ARRAY
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "collections" module
|
||||
#ifndef MICROPY_PY_COLLECTIONS
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
@@ -309,6 +359,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_SYS (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.maxsize" constant
|
||||
#ifndef MICROPY_PY_SYS_MAXSIZE
|
||||
#define MICROPY_PY_SYS_MAXSIZE (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "sys.exit" function
|
||||
#ifndef MICROPY_PY_SYS_EXIT
|
||||
#define MICROPY_PY_SYS_EXIT (0)
|
||||
@@ -319,6 +374,17 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_SYS_STDFILES (0)
|
||||
#endif
|
||||
|
||||
|
||||
// Extended modules
|
||||
|
||||
#ifndef MICROPY_PY_UCTYPES
|
||||
#define MICROPY_PY_UCTYPES (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_ZLIBD
|
||||
#define MICROPY_PY_ZLIBD (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to add builtins */
|
||||
|
||||
@@ -340,6 +406,14 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Miscellaneous settings */
|
||||
|
||||
// On embedded platforms, these will typically enable/disable irqs.
|
||||
#ifndef MICROPY_BEGIN_ATOMIC_SECTION
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION()
|
||||
#endif
|
||||
#ifndef MICROPY_END_ATOMIC_SECTION
|
||||
#define MICROPY_END_ATOMIC_SECTION()
|
||||
#endif
|
||||
|
||||
// Allow to override static modifier for global objects, e.g. to use with
|
||||
// object code analysis tools which don't support static symbols.
|
||||
#ifndef STATIC
|
||||
@@ -348,8 +422,8 @@ typedef double mp_float_t;
|
||||
|
||||
#define BITS_PER_BYTE (8)
|
||||
#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
|
||||
// machine_int_t value with most significant bit set
|
||||
#define WORD_MSBIT_HIGH (((machine_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
|
||||
// mp_int_t value with most significant bit set
|
||||
#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
|
||||
|
||||
#if !defined(MP_ENDIANNESS_LITTLE) && !defined(MP_ENDIANNESS_BIG)
|
||||
// Just because most archs are such?
|
||||
@@ -360,14 +434,20 @@ typedef double mp_float_t;
|
||||
#define MP_ENDIANNESS_LITTLE (0)
|
||||
#endif
|
||||
|
||||
// printf format spec to use for machine_int_t and friends
|
||||
// Make a pointer to RAM callable (eg set lower bit for Thumb code)
|
||||
// (This scheme won't work if we want to mix Thumb and normal ARM code.)
|
||||
#ifndef MICROPY_MAKE_POINTER_CALLABLE
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
|
||||
#endif
|
||||
|
||||
// printf format spec to use for mp_int_t and friends
|
||||
#ifndef INT_FMT
|
||||
#ifdef __LP64__
|
||||
// Archs where machine_int_t == long, long != int
|
||||
// Archs where mp_int_t == long, long != int
|
||||
#define UINT_FMT "%lu"
|
||||
#define INT_FMT "%ld"
|
||||
#else
|
||||
// Archs where machine_int_t == int
|
||||
// Archs where mp_int_t == int
|
||||
#define UINT_FMT "%u"
|
||||
#define INT_FMT "%d"
|
||||
#endif
|
||||
@@ -377,3 +457,8 @@ typedef double mp_float_t;
|
||||
#ifndef NORETURN
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
// Modifier for weak functions
|
||||
#ifndef MP_WEAK
|
||||
#define MP_WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
89
py/mpz.c
89
py/mpz.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "mpz.h"
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
|
||||
@@ -89,12 +89,12 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
|
||||
mpz_dbl_dig_t d = 0;
|
||||
for (uint i = jlen; i > 0; i--, idig--, jdig--) {
|
||||
d |= *jdig;
|
||||
*idig = d >> (DIG_SIZE - n_part);
|
||||
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
|
||||
d <<= DIG_SIZE;
|
||||
}
|
||||
|
||||
// store remaining bits
|
||||
*idig = d >> (DIG_SIZE - n_part);
|
||||
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
|
||||
idig -= n_whole - 1;
|
||||
memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
|
||||
|
||||
@@ -351,7 +351,7 @@ STATIC uint mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, mpz_dig_t *kdig
|
||||
modifies den_dig memory, but restors it to original state at end
|
||||
*/
|
||||
|
||||
STATIC void mpn_div(mpz_dig_t *num_dig, machine_uint_t *num_len, mpz_dig_t *den_dig, machine_uint_t den_len, mpz_dig_t *quo_dig, machine_uint_t *quo_len) {
|
||||
STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) {
|
||||
mpz_dig_t *orig_num_dig = num_dig;
|
||||
mpz_dig_t *orig_quo_dig = quo_dig;
|
||||
mpz_dig_t norm_shift = 0;
|
||||
@@ -502,12 +502,12 @@ void mpz_init_zero(mpz_t *z) {
|
||||
z->dig = NULL;
|
||||
}
|
||||
|
||||
void mpz_init_from_int(mpz_t *z, machine_int_t val) {
|
||||
void mpz_init_from_int(mpz_t *z, mp_int_t val) {
|
||||
mpz_init_zero(z);
|
||||
mpz_set_from_int(z, val);
|
||||
}
|
||||
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, machine_int_t val) {
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, mp_int_t val) {
|
||||
z->neg = 0;
|
||||
z->fixed_dig = 1;
|
||||
z->alloc = alloc;
|
||||
@@ -528,7 +528,7 @@ mpz_t *mpz_zero(void) {
|
||||
return z;
|
||||
}
|
||||
|
||||
mpz_t *mpz_from_int(machine_int_t val) {
|
||||
mpz_t *mpz_from_int(mp_int_t val) {
|
||||
mpz_t *z = mpz_zero();
|
||||
mpz_set_from_int(z, val);
|
||||
return z;
|
||||
@@ -594,10 +594,10 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
|
||||
memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
|
||||
}
|
||||
|
||||
void mpz_set_from_int(mpz_t *z, machine_int_t val) {
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
|
||||
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
|
||||
|
||||
machine_uint_t uval;
|
||||
mp_uint_t uval;
|
||||
if (val < 0) {
|
||||
z->neg = 1;
|
||||
uval = -val;
|
||||
@@ -704,7 +704,7 @@ int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
|
||||
#if 0
|
||||
// obsolete
|
||||
// compares mpz with an integer that fits within DIG_SIZE bits
|
||||
int mpz_cmp_sml_int(const mpz_t *z, machine_int_t sml_int) {
|
||||
int mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
|
||||
int cmp;
|
||||
if (z->neg == 0) {
|
||||
if (sml_int < 0) return 1;
|
||||
@@ -830,7 +830,7 @@ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
|
||||
/* computes dest = lhs << rhs
|
||||
can have dest, lhs the same
|
||||
*/
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
|
||||
if (lhs->len == 0 || rhs == 0) {
|
||||
mpz_set(dest, lhs);
|
||||
} else if (rhs < 0) {
|
||||
@@ -845,7 +845,7 @@ void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
/* computes dest = lhs >> rhs
|
||||
can have dest, lhs the same
|
||||
*/
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
|
||||
if (lhs->len == 0 || rhs == 0) {
|
||||
mpz_set(dest, lhs);
|
||||
} else if (rhs < 0) {
|
||||
@@ -1132,12 +1132,9 @@ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
|
||||
lcm(0, 0) = 0
|
||||
lcm(z, 0) = 0
|
||||
*/
|
||||
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2)
|
||||
{
|
||||
// braces below are required for compilation to succeed with CL, see bug report
|
||||
// https://connect.microsoft.com/VisualStudio/feedback/details/864169/compilation-error-when-braces-are-left-out-of-single-line-if-statement
|
||||
if (z1->len == 0 || z2->len == 0) {
|
||||
return mpz_zero();
|
||||
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
|
||||
if (z1->len == 0 || z2->len == 0) {
|
||||
return mpz_zero();
|
||||
}
|
||||
|
||||
mpz_t *gcd = mpz_gcd(z1, z2);
|
||||
@@ -1213,45 +1210,32 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO check that this correctly handles overflow in all cases
|
||||
machine_int_t mpz_as_int(const mpz_t *i) {
|
||||
machine_int_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
// must return actual int value if it fits in mp_int_t
|
||||
mp_int_t mpz_hash(const mpz_t *z) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = z->dig + z->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
machine_int_t oldval = val;
|
||||
while (--d >= z->dig) {
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow, return +/- "infinity"
|
||||
if (i->neg == 0) {
|
||||
// +infinity
|
||||
return ~WORD_MSBIT_HIGH;
|
||||
} else {
|
||||
// -infinity
|
||||
return WORD_MSBIT_HIGH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i->neg != 0) {
|
||||
if (z->neg != 0) {
|
||||
val = -val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// TODO check that this correctly handles overflow in all cases
|
||||
bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
|
||||
machine_int_t val = 0;
|
||||
bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
machine_int_t oldval = val;
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
if (val < oldval) {
|
||||
// overflow
|
||||
if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
|
||||
// will overflow
|
||||
return false;
|
||||
}
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
}
|
||||
|
||||
if (i->neg != 0) {
|
||||
@@ -1262,6 +1246,27 @@ bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
|
||||
if (i->neg != 0) {
|
||||
// can't represent signed values
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_uint_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
if (val > ((~0) >> DIG_SIZE)) {
|
||||
// will overflow
|
||||
return false;
|
||||
}
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mpz_as_float(const mpz_t *i) {
|
||||
mp_float_t val = 0;
|
||||
|
||||
27
py/mpz.h
27
py/mpz.h
@@ -29,27 +29,27 @@ typedef uint32_t mpz_dbl_dig_t;
|
||||
typedef int32_t mpz_dbl_dig_signed_t;
|
||||
|
||||
typedef struct _mpz_t {
|
||||
machine_uint_t neg : 1;
|
||||
machine_uint_t fixed_dig : 1;
|
||||
machine_uint_t alloc : 30;
|
||||
machine_uint_t len;
|
||||
mp_uint_t neg : 1;
|
||||
mp_uint_t fixed_dig : 1;
|
||||
mp_uint_t alloc : 30;
|
||||
mp_uint_t len;
|
||||
mpz_dig_t *dig;
|
||||
} mpz_t;
|
||||
|
||||
#define MPZ_DIG_SIZE (15) // see mpn_div for why this needs to be at most 15
|
||||
#define MPZ_NUM_DIG_FOR_INT (sizeof(machine_int_t) * 8 / MPZ_DIG_SIZE + 1)
|
||||
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
|
||||
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
|
||||
|
||||
// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
|
||||
#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
|
||||
|
||||
void mpz_init_zero(mpz_t *z);
|
||||
void mpz_init_from_int(mpz_t *z, machine_int_t val);
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, machine_int_t val);
|
||||
void mpz_init_from_int(mpz_t *z, mp_int_t val);
|
||||
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, mp_int_t val);
|
||||
void mpz_deinit(mpz_t *z);
|
||||
|
||||
mpz_t *mpz_zero();
|
||||
mpz_t *mpz_from_int(machine_int_t i);
|
||||
mpz_t *mpz_from_int(mp_int_t i);
|
||||
mpz_t *mpz_from_ll(long long i);
|
||||
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base);
|
||||
void mpz_free(mpz_t *z);
|
||||
@@ -57,7 +57,7 @@ void mpz_free(mpz_t *z);
|
||||
mpz_t *mpz_clone(const mpz_t *src);
|
||||
|
||||
void mpz_set(mpz_t *dest, const mpz_t *src);
|
||||
void mpz_set_from_int(mpz_t *z, machine_int_t src);
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t src);
|
||||
void mpz_set_from_ll(mpz_t *z, long long i);
|
||||
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base);
|
||||
|
||||
@@ -79,8 +79,8 @@ mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_abs_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_neg_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_not_inpl(mpz_t *dest, const mpz_t *z);
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
|
||||
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
|
||||
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
|
||||
void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
|
||||
@@ -96,8 +96,9 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
|
||||
mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs);
|
||||
mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs);
|
||||
|
||||
machine_int_t mpz_as_int(const mpz_t *z);
|
||||
bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value);
|
||||
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);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mpz_as_float(const mpz_t *z);
|
||||
#endif
|
||||
|
||||
136
py/nativeglue.c
Normal file
136
py/nativeglue.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "emitglue.h"
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
// convert a Micro Python object to a valid native value based on type
|
||||
mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) {
|
||||
DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type);
|
||||
switch (type & 3) {
|
||||
case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
|
||||
case MP_NATIVE_TYPE_BOOL:
|
||||
case MP_NATIVE_TYPE_INT:
|
||||
case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
|
||||
default: assert(0); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// convert a native value to a Micro Python object based on type
|
||||
mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) {
|
||||
DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
|
||||
switch (type & 3) {
|
||||
case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
|
||||
case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
|
||||
case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
|
||||
case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
|
||||
default: assert(0); return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper that accepts n_args and n_kw in one argument
|
||||
// (native emitter can only pass at most 3 arguments to a function)
|
||||
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args) {
|
||||
return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
|
||||
}
|
||||
|
||||
// wrapper that makes raise obj and raises it
|
||||
NORETURN void mp_native_raise(mp_obj_t o) {
|
||||
nlr_raise(mp_make_raise_obj(o));
|
||||
}
|
||||
|
||||
// these must correspond to the respective enum in runtime0.h
|
||||
void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_convert_obj_to_native,
|
||||
mp_convert_native_to_obj,
|
||||
mp_load_const_int,
|
||||
mp_load_const_dec,
|
||||
mp_load_const_str,
|
||||
mp_load_const_bytes,
|
||||
mp_load_name,
|
||||
mp_load_global,
|
||||
mp_load_build_class,
|
||||
mp_load_attr,
|
||||
mp_load_method,
|
||||
mp_store_name,
|
||||
mp_store_global,
|
||||
mp_store_attr,
|
||||
mp_obj_subscr,
|
||||
mp_obj_is_true,
|
||||
mp_unary_op,
|
||||
mp_binary_op,
|
||||
mp_obj_new_tuple,
|
||||
mp_obj_new_list,
|
||||
mp_obj_list_append,
|
||||
mp_obj_new_dict,
|
||||
mp_obj_dict_store,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
mp_obj_new_set,
|
||||
mp_obj_set_store,
|
||||
#endif
|
||||
mp_make_function_from_raw_code,
|
||||
mp_native_call_function_n_kw,
|
||||
mp_call_method_n_kw,
|
||||
mp_getiter,
|
||||
mp_iternext,
|
||||
nlr_push,
|
||||
nlr_pop,
|
||||
mp_native_raise,
|
||||
mp_import_name,
|
||||
mp_import_from,
|
||||
mp_import_all,
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
mp_obj_new_slice,
|
||||
#endif
|
||||
mp_unpack_sequence,
|
||||
mp_unpack_ex,
|
||||
};
|
||||
|
||||
/*
|
||||
void mp_f_vector(mp_fun_kind_t fun_kind) {
|
||||
(mp_f_table[fun_kind])();
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
3
py/nlr.h
3
py/nlr.h
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct _nlr_buf_t nlr_buf_t;
|
||||
struct _nlr_buf_t {
|
||||
@@ -44,7 +45,7 @@ struct _nlr_buf_t {
|
||||
#else
|
||||
void *regs[8];
|
||||
#endif
|
||||
#elif defined(__thumb2__)
|
||||
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
|
||||
void *regs[10];
|
||||
#else
|
||||
#define MICROPY_NLR_SETJMP (1)
|
||||
|
||||
@@ -24,19 +24,21 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__thumb2__) && !MICROPY_NLR_SETJMP
|
||||
/* thumb callee save: bx, bp, sp, r12, r14, r14, r15 */
|
||||
#if !MICROPY_NLR_SETJMP && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
|
||||
/* arm callee save: bx, bp, sp, r12, r14, r14, r15 */
|
||||
|
||||
.syntax unified
|
||||
/*.cpu cortex-m4*/
|
||||
.thumb
|
||||
/*.thumb*/
|
||||
.text
|
||||
.align 2
|
||||
|
||||
/* uint nlr_push(r0=nlr_buf_t *nlr) */
|
||||
.global nlr_push
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_push, %function
|
||||
nlr_push:
|
||||
str lr, [r0, #8] @ store lr into nlr_buf
|
||||
@@ -64,8 +66,10 @@ nlr_push:
|
||||
|
||||
@ void nlr_pop()
|
||||
.global nlr_pop
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_pop, %function
|
||||
nlr_pop:
|
||||
ldr r3, .L5 @ load addr of nlr_top
|
||||
@@ -80,8 +84,10 @@ nlr_pop:
|
||||
|
||||
/* void nlr_jump(r0=uint val) */
|
||||
.global nlr_jump
|
||||
#if defined(__thumb2__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
.type nlr_jump, %function
|
||||
nlr_jump:
|
||||
ldr r3, .L2 @ load addr of nlr_top
|
||||
|
||||
53
py/obj.c
53
py/obj.c
@@ -24,6 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
@@ -33,8 +34,11 @@
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
@@ -59,6 +63,8 @@ void printf_wrapper(void *env, const char *fmt, ...) {
|
||||
}
|
||||
|
||||
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
// There can be data structures nested too deep, or just recursive
|
||||
MP_STACK_CHECK();
|
||||
#if !NDEBUG
|
||||
if (o_in == NULL) {
|
||||
print(env, "(nil)");
|
||||
@@ -80,7 +86,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
// helper function to print an exception with traceback
|
||||
void mp_obj_print_exception(mp_obj_t exc) {
|
||||
if (mp_obj_is_exception_instance(exc)) {
|
||||
machine_uint_t n, *values;
|
||||
mp_uint_t n, *values;
|
||||
mp_obj_exception_get_traceback(exc, &n, &values);
|
||||
if (n > 0) {
|
||||
assert(n % 3 == 0);
|
||||
@@ -142,23 +148,25 @@ bool mp_obj_is_callable(mp_obj_t o_in) {
|
||||
return mp_obj_get_type(o_in)->call != NULL;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_hash(mp_obj_t o_in) {
|
||||
mp_int_t mp_obj_hash(mp_obj_t o_in) {
|
||||
if (o_in == mp_const_false) {
|
||||
return 0; // needs to hash to same as the integer 0, since False==0
|
||||
} else if (o_in == mp_const_true) {
|
||||
return 1; // needs to hash to same as the integer 1, since True==1
|
||||
} else if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_int)) {
|
||||
return mp_obj_int_hash(o_in);
|
||||
} else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return mp_obj_str_get_hash(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {
|
||||
return (machine_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_fun_native) || MP_OBJ_IS_TYPE(o_in, &mp_type_fun_bc)) {
|
||||
return (machine_int_t)o_in;
|
||||
return (mp_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_FUN(o_in)) {
|
||||
return (mp_int_t)o_in;
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) {
|
||||
return mp_obj_tuple_hash(o_in);
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) {
|
||||
return (machine_int_t)o_in;
|
||||
return (mp_int_t)o_in;
|
||||
|
||||
// TODO hash class and instances
|
||||
// TODO delegate to __hash__ method if it exists
|
||||
@@ -222,7 +230,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_get_int(mp_const_obj_t arg) {
|
||||
mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
|
||||
// This function essentially performs implicit type conversion to int
|
||||
// Note that Python does NOT provide implicit type conversion from
|
||||
// float to int in the core expression language, try some_list[1.0].
|
||||
@@ -241,8 +249,8 @@ machine_int_t mp_obj_get_int(mp_const_obj_t arg) {
|
||||
|
||||
// returns false if arg is not of integral type
|
||||
// returns true and sets *value if it is of integral type
|
||||
// can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value) {
|
||||
// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
|
||||
if (arg == mp_const_false) {
|
||||
*value = 0;
|
||||
} else if (arg == mp_const_true) {
|
||||
@@ -274,6 +282,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
if (arg == mp_const_false) {
|
||||
*real = 0;
|
||||
@@ -297,6 +306,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
|
||||
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
|
||||
@@ -325,8 +335,8 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
|
||||
}
|
||||
|
||||
// is_slice determines whether the index is a slice index
|
||||
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice) {
|
||||
machine_int_t i;
|
||||
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) {
|
||||
mp_int_t i;
|
||||
if (MP_OBJ_IS_SMALL_INT(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
@@ -350,10 +360,25 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index,
|
||||
return i;
|
||||
}
|
||||
|
||||
// will raise a TypeError if object has no length
|
||||
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) {
|
||||
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)));
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
// may return MP_OBJ_NULL
|
||||
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
|
||||
if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
|
||||
if (
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
// It's simple - unicode is slow, non-unicode is fast
|
||||
MP_OBJ_IS_STR(o_in) ||
|
||||
#endif
|
||||
MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_obj_str_get_len(o_in));
|
||||
} else {
|
||||
mp_obj_type_t *type = mp_obj_get_type(o_in);
|
||||
if (type->unary_op != NULL) {
|
||||
@@ -395,7 +420,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
|
||||
return false;
|
||||
}
|
||||
int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);
|
||||
if (ret != 0 || bufinfo->buf == NULL) {
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
132
py/obj.h
132
py/obj.h
@@ -35,11 +35,6 @@
|
||||
typedef machine_ptr_t mp_obj_t;
|
||||
typedef machine_const_ptr_t mp_const_obj_t;
|
||||
|
||||
// Integers that fit in a pointer have this type
|
||||
// (do we need to expose this in the public API?)
|
||||
|
||||
typedef machine_int_t mp_small_int_t;
|
||||
|
||||
// Anything that wants to be a Micro Python object must have
|
||||
// mp_obj_base_t as its first member (except small ints and qstrs)
|
||||
|
||||
@@ -73,25 +68,27 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
|
||||
// These macros check for small int, qstr or object, and access small int and qstr values
|
||||
|
||||
// these macros have now become inline functions; see below
|
||||
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
|
||||
//#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
|
||||
//#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
|
||||
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking a string, use below macro for that
|
||||
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_int_t)(o)) & 1) != 0)
|
||||
//#define MP_OBJ_IS_QSTR(o) ((((mp_int_t)(o)) & 3) == 2)
|
||||
//#define MP_OBJ_IS_OBJ(o) ((((mp_int_t)(o)) & 3) == 0)
|
||||
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
|
||||
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
|
||||
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
|
||||
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)(o))->type->binary_op == mp_obj_str_binary_op))
|
||||
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type->binary_op == mp_obj_fun_binary_op))
|
||||
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_small_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((small_int) << 1) | 1))
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
|
||||
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_small_int_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((machine_uint_t)qstr) << 2) | 2))
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_int_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((mp_uint_t)(qstr)) << 2) | 2))
|
||||
|
||||
// These macros are used to declare and define constant function objects
|
||||
// You can put "static" in front of the definitions to make them local
|
||||
|
||||
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_native_t obj_name
|
||||
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name
|
||||
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_native_t obj_name = {{&mp_type_fun_native}, is_kw, n_args_min, n_args_max, (void *)fun_name}
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_builtin_t obj_name = {{&mp_type_fun_builtin}, is_kw, n_args_min, n_args_max, (void *)fun_name}
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 0, 0, (mp_fun_0_t)fun_name)
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 1, 1, (mp_fun_1_t)fun_name)
|
||||
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 2, 2, (mp_fun_2_t)fun_name)
|
||||
@@ -137,10 +134,10 @@ typedef struct _mp_map_elem_t {
|
||||
// would also need a trucated dict structure
|
||||
|
||||
typedef struct _mp_map_t {
|
||||
machine_uint_t all_keys_are_qstrs : 1;
|
||||
machine_uint_t table_is_fixed_array : 1;
|
||||
machine_uint_t used : (8 * sizeof(machine_uint_t) - 2);
|
||||
machine_uint_t alloc;
|
||||
mp_uint_t all_keys_are_qstrs : 1;
|
||||
mp_uint_t table_is_fixed_array : 1;
|
||||
mp_uint_t used : (8 * sizeof(mp_uint_t) - 2);
|
||||
mp_uint_t alloc;
|
||||
mp_map_elem_t *table;
|
||||
} mp_map_t;
|
||||
|
||||
@@ -151,7 +148,7 @@ typedef enum _mp_map_lookup_kind_t {
|
||||
MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2
|
||||
} mp_map_lookup_kind_t;
|
||||
|
||||
static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
|
||||
static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, mp_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
|
||||
|
||||
void mp_map_init(mp_map_t *map, int n);
|
||||
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
|
||||
@@ -165,12 +162,12 @@ void mp_map_dump(mp_map_t *map);
|
||||
// Underlying set implementation (not set object)
|
||||
|
||||
typedef struct _mp_set_t {
|
||||
machine_uint_t alloc;
|
||||
machine_uint_t used;
|
||||
mp_uint_t alloc;
|
||||
mp_uint_t used;
|
||||
mp_obj_t *table;
|
||||
} mp_set_t;
|
||||
|
||||
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
|
||||
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, mp_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
|
||||
|
||||
void mp_set_init(mp_set_t *set, int n);
|
||||
mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
|
||||
@@ -183,7 +180,6 @@ typedef mp_obj_t (*mp_fun_0_t)(void);
|
||||
typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*mp_fun_t)(void);
|
||||
typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *);
|
||||
typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
|
||||
|
||||
@@ -215,8 +211,8 @@ typedef struct _mp_buffer_info_t {
|
||||
// them with ver = sizeof(struct). Cons: overkill for *micro*?
|
||||
//int ver; // ?
|
||||
|
||||
void *buf;
|
||||
machine_int_t len; // in bytes
|
||||
void *buf; // can be NULL if len == 0
|
||||
mp_int_t len; // in bytes
|
||||
int typecode; // as per binary.h
|
||||
|
||||
// Rationale: to load arbitrary-sized sprites directly to LCD
|
||||
@@ -227,19 +223,20 @@ typedef struct _mp_buffer_info_t {
|
||||
#define MP_BUFFER_WRITE (2)
|
||||
#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE)
|
||||
typedef struct _mp_buffer_p_t {
|
||||
machine_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
} mp_buffer_p_t;
|
||||
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
// Stream protocol
|
||||
#define MP_STREAM_ERROR (-1)
|
||||
typedef struct _mp_stream_p_t {
|
||||
// On error, functions should return -1 and fill in *errcode (values are
|
||||
// implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
machine_int_t (*read)(mp_obj_t obj, void *buf, machine_uint_t size, int *errcode);
|
||||
machine_int_t (*write)(mp_obj_t obj, const void *buf, machine_uint_t size, int *errcode);
|
||||
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
|
||||
// are implementation-dependent, but will be exposed to user, e.g. via exception).
|
||||
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
|
||||
// add seek() ?
|
||||
int is_bytes : 1;
|
||||
int is_text : 1; // default is bytes, set this for text stream
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
@@ -308,7 +305,7 @@ extern const mp_obj_type_t mp_type_zip;
|
||||
extern const mp_obj_type_t mp_type_array;
|
||||
extern const mp_obj_type_t mp_type_super;
|
||||
extern const mp_obj_type_t mp_type_gen_instance;
|
||||
extern const mp_obj_type_t mp_type_fun_native;
|
||||
extern const mp_obj_type_t mp_type_fun_builtin;
|
||||
extern const mp_obj_type_t mp_type_fun_bc;
|
||||
extern const mp_obj_type_t mp_type_module;
|
||||
extern const mp_obj_type_t mp_type_staticmethod;
|
||||
@@ -316,6 +313,7 @@ extern const mp_obj_type_t mp_type_classmethod;
|
||||
extern const mp_obj_type_t mp_type_property;
|
||||
extern const mp_obj_type_t mp_type_stringio;
|
||||
extern const mp_obj_type_t mp_type_bytesio;
|
||||
extern const mp_obj_type_t mp_type_reversed;
|
||||
|
||||
// Exceptions
|
||||
extern const mp_obj_type_t mp_type_BaseException;
|
||||
@@ -365,8 +363,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);
|
||||
mp_obj_t mp_obj_new_none(void);
|
||||
mp_obj_t mp_obj_new_bool(bool value);
|
||||
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value);
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value);
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
|
||||
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base);
|
||||
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
|
||||
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already);
|
||||
@@ -380,8 +378,10 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
|
||||
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
|
||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
|
||||
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
|
||||
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
|
||||
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
|
||||
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
||||
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
|
||||
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
|
||||
@@ -406,20 +406,20 @@ void mp_obj_print_exception(mp_obj_t exc);
|
||||
int mp_obj_is_true(mp_obj_t arg);
|
||||
|
||||
// TODO make these all lower case when they have proven themselves
|
||||
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 0); }
|
||||
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 1) != 0); }
|
||||
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); }
|
||||
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); }
|
||||
//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that
|
||||
//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int
|
||||
static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
|
||||
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 2); }
|
||||
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); }
|
||||
//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); }
|
||||
|
||||
bool mp_obj_is_callable(mp_obj_t o_in);
|
||||
machine_int_t mp_obj_hash(mp_obj_t o_in);
|
||||
mp_int_t mp_obj_hash(mp_obj_t o_in);
|
||||
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
|
||||
|
||||
machine_int_t mp_obj_get_int(mp_const_obj_t arg);
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value);
|
||||
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
|
||||
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_get_float(mp_obj_t self_in);
|
||||
void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
|
||||
@@ -427,26 +427,27 @@ void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
|
||||
//qstr mp_obj_get_qstr(mp_obj_t arg);
|
||||
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items);
|
||||
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items);
|
||||
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice);
|
||||
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice);
|
||||
mp_obj_t mp_obj_len(mp_obj_t o_in);
|
||||
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return MP_OBJ_NULL */
|
||||
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);
|
||||
|
||||
// bool
|
||||
// TODO make lower case when it has proven itself
|
||||
static inline mp_obj_t MP_BOOL(machine_int_t x) { return x ? mp_const_true : mp_const_false; }
|
||||
static inline mp_obj_t MP_BOOL(mp_int_t x) { return x ? mp_const_true : mp_const_false; }
|
||||
|
||||
// cell
|
||||
mp_obj_t mp_obj_cell_get(mp_obj_t self_in);
|
||||
void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
|
||||
|
||||
// int
|
||||
// For long int, returns value truncated to machine_int_t
|
||||
machine_int_t mp_obj_int_get(mp_const_obj_t self_in);
|
||||
// For long int, returns value truncated to mp_int_t
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t mp_obj_int_as_float(mp_obj_t self_in);
|
||||
#endif
|
||||
// Will raise exception if value doesn't fit into machine_int_t
|
||||
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
|
||||
// Will raise exception if value doesn't fit into mp_int_t
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
|
||||
|
||||
// exception
|
||||
#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
|
||||
@@ -454,14 +455,17 @@ bool mp_obj_is_exception_type(mp_obj_t self_in);
|
||||
bool mp_obj_is_exception_instance(mp_obj_t self_in);
|
||||
bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type);
|
||||
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block);
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values);
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block);
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
|
||||
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
|
||||
void mp_init_emergency_exception_buf(void);
|
||||
|
||||
// str
|
||||
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
|
||||
mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in);
|
||||
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len);
|
||||
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);
|
||||
uint mp_obj_str_get_hash(mp_obj_t self_in);
|
||||
uint mp_obj_str_get_len(mp_obj_t self_in);
|
||||
@@ -469,7 +473,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve
|
||||
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
|
||||
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len);
|
||||
mp_obj_t mp_obj_str_intern(mp_obj_t str);
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len);
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len, bool is_bytes);
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// float
|
||||
@@ -488,7 +492,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
|
||||
// tuple
|
||||
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
|
||||
void mp_obj_tuple_del(mp_obj_t self_in);
|
||||
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in);
|
||||
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
|
||||
|
||||
// list
|
||||
struct _mp_obj_list_t;
|
||||
@@ -523,17 +527,15 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items);
|
||||
|
||||
// functions
|
||||
#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below
|
||||
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
|
||||
typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM
|
||||
mp_obj_base_t base;
|
||||
bool is_kw : 1;
|
||||
uint n_args_min : 15; // inclusive
|
||||
uint n_args_max : 16; // inclusive
|
||||
void *fun;
|
||||
// TODO add mp_map_t *globals
|
||||
// for const function objects, make an empty, const map
|
||||
// such functions won't be able to access the global scope, but that's probably okay
|
||||
} mp_obj_fun_native_t;
|
||||
mp_uint_t n_args_min : 15; // inclusive
|
||||
mp_uint_t n_args_max : 16; // inclusive
|
||||
void *fun; // must be a pointer to a callable function in ROM
|
||||
} mp_obj_fun_builtin_t;
|
||||
|
||||
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||
const char *mp_obj_fun_get_name(mp_const_obj_t fun);
|
||||
const char *mp_obj_code_get_name(const byte *code_info);
|
||||
|
||||
@@ -562,14 +564,14 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
|
||||
|
||||
// slice indexes resolved to particular sequence
|
||||
typedef struct {
|
||||
machine_uint_t start;
|
||||
machine_uint_t stop;
|
||||
machine_int_t step;
|
||||
mp_uint_t start;
|
||||
mp_uint_t stop;
|
||||
mp_int_t step;
|
||||
} mp_bound_slice_t;
|
||||
|
||||
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
|
||||
bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
|
||||
#endif
|
||||
#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))
|
||||
#define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); }
|
||||
|
||||
@@ -37,19 +37,22 @@
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
|
||||
typedef struct _mp_obj_array_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t typecode : 8;
|
||||
mp_uint_t typecode : 8;
|
||||
// free is number of unused elements after len used elements
|
||||
// alloc size = len + free
|
||||
machine_uint_t free : (8 * sizeof(machine_uint_t) - 8);
|
||||
machine_uint_t len; // in elements
|
||||
mp_uint_t free : (8 * sizeof(mp_uint_t) - 8);
|
||||
mp_uint_t len; // in elements
|
||||
void *items;
|
||||
} mp_obj_array_t;
|
||||
|
||||
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
|
||||
STATIC mp_obj_array_t *array_new(char typecode, uint n);
|
||||
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
|
||||
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
/******************************************************************************/
|
||||
/* array */
|
||||
@@ -57,8 +60,8 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
|
||||
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
if (o->typecode == BYTEARRAY_TYPECODE) {
|
||||
print(env, "bytearray(b", o->typecode);
|
||||
mp_str_print_quoted(print, env, o->items, o->len);
|
||||
print(env, "bytearray(b");
|
||||
mp_str_print_quoted(print, env, o->items, o->len, true);
|
||||
} else {
|
||||
print(env, "array('%c'", o->typecode);
|
||||
if (o->len > 0) {
|
||||
@@ -144,6 +147,22 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_EQUAL: {
|
||||
mp_buffer_info_t lhs_bufinfo;
|
||||
mp_buffer_info_t rhs_bufinfo;
|
||||
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
|
||||
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
}
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
|
||||
mp_obj_array_t *self = self_in;
|
||||
@@ -204,7 +223,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
|
||||
}
|
||||
}
|
||||
|
||||
STATIC machine_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
mp_obj_array_t *o = o_in;
|
||||
bufinfo->buf = o->items;
|
||||
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
|
||||
@@ -225,6 +244,7 @@ const mp_obj_type_t mp_type_array = {
|
||||
.make_new = array_make_new,
|
||||
.getiter = array_iterator_new,
|
||||
.unary_op = array_unary_op,
|
||||
.binary_op = array_binary_op,
|
||||
.subscr = array_subscr,
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
@@ -237,6 +257,7 @@ const mp_obj_type_t mp_type_bytearray = {
|
||||
.make_new = bytearray_make_new,
|
||||
.getiter = array_iterator_new,
|
||||
.unary_op = array_unary_op,
|
||||
.binary_op = array_binary_op,
|
||||
.subscr = array_subscr,
|
||||
.buffer_p = { .get_buffer = array_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&array_locals_dict,
|
||||
@@ -283,7 +304,7 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
|
||||
typedef struct _mp_obj_array_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_array_t *array;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_array_it_t;
|
||||
|
||||
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
|
||||
@@ -310,3 +331,5 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
|
||||
@@ -61,7 +61,7 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
|
||||
}
|
||||
|
||||
STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
|
||||
machine_int_t value = ((mp_obj_bool_t*)o_in)->value;
|
||||
mp_int_t value = ((mp_obj_bool_t*)o_in)->value;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return o_in;
|
||||
case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value);
|
||||
@@ -74,7 +74,7 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
|
||||
|
||||
STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in);
|
||||
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(mp_obj_is_true(lhs_in)), rhs_in);
|
||||
}
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
typedef struct _mp_obj_closure_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t fun;
|
||||
machine_uint_t n_closed;
|
||||
mp_uint_t n_closed;
|
||||
mp_obj_t closed[];
|
||||
} mp_obj_closure_t;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -132,6 +132,15 @@ STATIC mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
|
||||
}
|
||||
|
||||
STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_complex_t *self = self_in;
|
||||
if (attr == MP_QSTR_real) {
|
||||
dest[0] = mp_obj_new_float(self->real);
|
||||
} else if (attr == MP_QSTR_imag) {
|
||||
dest[0] = mp_obj_new_float(self->imag);
|
||||
}
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_complex = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_complex,
|
||||
@@ -139,6 +148,7 @@ const mp_obj_type_t mp_type_complex = {
|
||||
.make_new = complex_make_new,
|
||||
.unary_op = complex_unary_op,
|
||||
.binary_op = complex_binary_op,
|
||||
.load_attr = complex_load_attr,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {
|
||||
|
||||
14
py/objdict.c
14
py/objdict.c
@@ -75,7 +75,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
|
||||
mp_obj_dict_t *self = self_in;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
@@ -94,10 +94,10 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
machine_uint_t size = o->map.alloc;
|
||||
mp_uint_t size = o->map.alloc;
|
||||
mp_map_t *map = &o->map;
|
||||
|
||||
for (machine_uint_t i = 0; i < size; i++) {
|
||||
for (mp_uint_t i = 0; i < size; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
|
||||
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, map->table[i].key, MP_MAP_LOOKUP);
|
||||
if (elem == NULL || !mp_obj_equal(map->table[i].value, elem->value)) {
|
||||
@@ -155,12 +155,12 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
typedef struct _mp_obj_dict_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *dict;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_dict_it_t;
|
||||
|
||||
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
|
||||
mp_obj_dict_it_t *self = self_in;
|
||||
machine_uint_t max = self->dict->map.alloc;
|
||||
mp_uint_t max = self->dict->map.alloc;
|
||||
mp_map_t *map = &self->dict->map;
|
||||
|
||||
for (int i = self->cur; i < max; i++) {
|
||||
@@ -374,7 +374,7 @@ STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs)
|
||||
}
|
||||
|
||||
// update the dict with any keyword args
|
||||
for (machine_uint_t i = 0; i < kwargs->alloc; i++) {
|
||||
for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
|
||||
mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value;
|
||||
}
|
||||
@@ -403,7 +403,7 @@ typedef struct _mp_obj_dict_view_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_dict_view_kind_t kind;
|
||||
mp_obj_dict_it_t *iter;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_dict_view_it_t;
|
||||
|
||||
typedef struct _mp_obj_dict_view_t {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -36,7 +36,7 @@
|
||||
typedef struct _mp_obj_enumerate_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t iter;
|
||||
machine_int_t cur;
|
||||
mp_int_t cur;
|
||||
} mp_obj_enumerate_t;
|
||||
|
||||
STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in);
|
||||
@@ -45,7 +45,7 @@ STATIC const mp_arg_t enumerate_make_new_args[] = {
|
||||
{ MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_start, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
#define ENUMERATE_MAKE_NEW_NUM_ARGS ARRAY_SIZE(enumerate_make_new_args)
|
||||
#define ENUMERATE_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(enumerate_make_new_args)
|
||||
|
||||
STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
|
||||
121
py/objexcept.c
121
py/objexcept.c
@@ -27,16 +27,20 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "objstr.h"
|
||||
#include "objtuple.h"
|
||||
#include "objtype.h"
|
||||
#include "runtime.h"
|
||||
#include "runtime0.h"
|
||||
#include "gc.h"
|
||||
|
||||
typedef struct _mp_obj_exception_t {
|
||||
mp_obj_base_t base;
|
||||
@@ -50,6 +54,53 @@ const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_
|
||||
// Local non-heap memory for allocating an exception when we run out of RAM
|
||||
STATIC mp_obj_exception_t mp_emergency_exception_obj;
|
||||
|
||||
// Optionally allocated buffer for storing the first argument of an exception
|
||||
// allocated when the heap is locked.
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
|
||||
STATIC byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
|
||||
#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
// Nothing to do since the buffer was declared statically. We put this
|
||||
// definition here so that the calling code can call this function
|
||||
// regardless of how its configured (makes the calling code a bit cleaner).
|
||||
}
|
||||
|
||||
#else
|
||||
STATIC mp_int_t mp_emergency_exception_buf_size = 0;
|
||||
STATIC byte *mp_emergency_exception_buf = NULL;
|
||||
|
||||
void mp_init_emergency_exception_buf(void) {
|
||||
mp_emergency_exception_buf_size = 0;
|
||||
mp_emergency_exception_buf = NULL;
|
||||
}
|
||||
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
|
||||
mp_int_t size = mp_obj_get_int(size_in);
|
||||
void *buf = NULL;
|
||||
if (size > 0) {
|
||||
buf = m_malloc(size);
|
||||
}
|
||||
|
||||
int old_size = mp_emergency_exception_buf_size;
|
||||
void *old_buf = mp_emergency_exception_buf;
|
||||
|
||||
// Update the 2 variables atomically so that an interrupt can't occur
|
||||
// between the assignments.
|
||||
mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
mp_emergency_exception_buf_size = size;
|
||||
mp_emergency_exception_buf = buf;
|
||||
MICROPY_END_ATOMIC_SECTION(irq_state);
|
||||
|
||||
if (old_buf != NULL) {
|
||||
m_free(old_buf, old_size);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
|
||||
// Instance of GeneratorExit exception - needed by generator.close()
|
||||
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
||||
// definition module-private so far, have it here.
|
||||
@@ -267,6 +318,50 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
o->args = mp_const_empty_tuple;
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
// If the user has provided a buffer, then we try to create a tuple
|
||||
// of length 1, which has a string object and the string data.
|
||||
|
||||
if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) {
|
||||
mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf;
|
||||
mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1];
|
||||
|
||||
tuple->base.type = &mp_type_tuple;
|
||||
tuple->len = 1;
|
||||
tuple->items[0] = str;
|
||||
|
||||
byte *str_data = (byte *)&str[1];
|
||||
uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size
|
||||
- str_data;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
str->len = vsnprintf((char *)str_data, max_len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
str->base.type = &mp_type_str;
|
||||
str->hash = qstr_compute_hash(str_data, str->len);
|
||||
str->data = str_data;
|
||||
|
||||
o->args = tuple;
|
||||
|
||||
uint offset = &str_data[str->len] - mp_emergency_exception_buf;
|
||||
offset += sizeof(void *) - 1;
|
||||
offset &= ~(sizeof(void *) - 1);
|
||||
|
||||
if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) {
|
||||
// We have room to store some traceback.
|
||||
mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset);
|
||||
list->base.type = &mp_type_list;
|
||||
list->items = (mp_obj_t)&list[1];
|
||||
list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]);
|
||||
list->len = 0;
|
||||
|
||||
o->traceback = list;
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
} else {
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
@@ -334,19 +429,35 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
|
||||
self->traceback = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) {
|
||||
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
if (gc_is_locked()) {
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
// We can't allocate any memory, and no memory has been
|
||||
// pre-allocated, so there is nothing else we can do.
|
||||
return;
|
||||
}
|
||||
mp_obj_list_t *list = self->traceback;
|
||||
if (list->alloc <= (list->len + 3)) {
|
||||
// There is some preallocated memory, but not enough to store an
|
||||
// entire record.
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
self->traceback = mp_obj_new_list(0, NULL);
|
||||
}
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)file);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)line);
|
||||
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)block);
|
||||
}
|
||||
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) {
|
||||
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values) {
|
||||
GET_NATIVE_EXCEPTION(self, self_in);
|
||||
|
||||
if (self->traceback == MP_OBJ_NULL) {
|
||||
|
||||
@@ -102,9 +102,12 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
|
||||
|
||||
STATIC mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_float_t *lhs = lhs_in;
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
|
||||
return mp_obj_complex_binary_op(op, lhs->value, 0, rhs_in);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return mp_obj_float_binary_op(op, lhs->value, rhs_in);
|
||||
}
|
||||
}
|
||||
|
||||
259
py/objfun.c
259
py/objfun.c
@@ -39,6 +39,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "bc.h"
|
||||
#include "stackctrl.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -46,12 +47,9 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* native functions */
|
||||
|
||||
// mp_obj_fun_native_t defined in obj.h
|
||||
|
||||
STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
// This binary_op method is used for all function types, and is also
|
||||
// used to determine if an object is of generic function type.
|
||||
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_EQUAL:
|
||||
// These objects can be equal only if it's the same underlying structure,
|
||||
@@ -61,9 +59,14 @@ STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
|
||||
mp_obj_fun_native_t *self = self_in;
|
||||
/******************************************************************************/
|
||||
/* builtin functions */
|
||||
|
||||
// mp_obj_fun_builtin_t defined in obj.h
|
||||
|
||||
STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin));
|
||||
mp_obj_fun_builtin_t *self = self_in;
|
||||
|
||||
// check number of arguments
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
|
||||
@@ -106,26 +109,16 @@ STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const
|
||||
}
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_fun_native = {
|
||||
const mp_obj_type_t mp_type_fun_builtin = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_native_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.call = fun_builtin_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
// fun must have the correct signature for n_args fixed arguments
|
||||
mp_obj_t mp_make_function_n(int n_args, void *fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args;
|
||||
o->n_args_max = n_args;
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
|
||||
#if 0 // currently unused, and semi-obsolete
|
||||
mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args_min;
|
||||
@@ -136,7 +129,7 @@ mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
|
||||
|
||||
// min and max are inclusive
|
||||
mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->is_kw = false;
|
||||
o->n_args_min = n_args_min;
|
||||
@@ -144,6 +137,7 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var
|
||||
o->fun = fun;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* byte code functions */
|
||||
@@ -178,7 +172,7 @@ STATIC void dump_args(const mp_obj_t *a, int sz) {
|
||||
#define dump_args(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, uint given) {
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
// Generic message, to be reused for other argument issues
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
@@ -196,16 +190,18 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui
|
||||
// With this macro you can tune the maximum number of function state bytes
|
||||
// that will be allocated on the stack. Any function that needs more
|
||||
// than this will use the heap.
|
||||
#define VM_MAX_STATE_ON_STACK (10 * sizeof(machine_uint_t))
|
||||
#define VM_MAX_STATE_ON_STACK (10 * sizeof(mp_uint_t))
|
||||
|
||||
// Set this to enable a simple stack overflow check.
|
||||
#define VM_DETECT_STACK_OVERFLOW (0)
|
||||
|
||||
// code_state should have ->ip filled in (pointing past code info block),
|
||||
// as well as ->n_state.
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||
// usage for the common case of positional only args.
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
machine_uint_t n_state = code_state->n_state;
|
||||
mp_uint_t n_state = code_state->n_state;
|
||||
const byte *ip = code_state->ip;
|
||||
|
||||
code_state->code_info = self->bytecode;
|
||||
@@ -240,7 +236,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
|
||||
if (n_kw == 0 && !self->has_def_kw_args) {
|
||||
if (n_args >= self->n_pos_args - self->n_def_args) {
|
||||
// given enough arguments, but may need to use some default arguments
|
||||
for (uint i = n_args; i < self->n_pos_args; i++) {
|
||||
for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
|
||||
code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
|
||||
}
|
||||
} else {
|
||||
@@ -250,7 +246,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
|
||||
}
|
||||
|
||||
// copy positional args into state
|
||||
for (uint i = 0; i < n_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
code_state->state[n_state - 1 - i] = args[i];
|
||||
}
|
||||
|
||||
@@ -266,9 +262,9 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
|
||||
*var_pos_kw_args = dict;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < n_kw; i++) {
|
||||
for (mp_uint_t i = 0; i < n_kw; i++) {
|
||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||
for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
if (arg_name == self->args[j]) {
|
||||
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
@@ -311,7 +307,7 @@ continue2:;
|
||||
|
||||
// Check that all mandatory keyword args are specified
|
||||
// Fill in default kw args if we have them
|
||||
for (uint i = 0; i < self->n_kwonly_args; i++) {
|
||||
for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
|
||||
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (self->has_def_kw_args) {
|
||||
@@ -338,8 +334,8 @@ continue2:;
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
for (uint n_local = *ip++; n_local > 0; n_local--) {
|
||||
uint local_num = *ip++;
|
||||
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
|
||||
mp_uint_t local_num = *ip++;
|
||||
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
|
||||
}
|
||||
|
||||
@@ -353,8 +349,7 @@ continue2:;
|
||||
|
||||
|
||||
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||
// usage for the common case of positional only args.
|
||||
MP_STACK_CHECK();
|
||||
|
||||
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
|
||||
DEBUG_printf("Input pos args: ");
|
||||
@@ -367,12 +362,12 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
||||
const byte *ip = self->bytecode;
|
||||
|
||||
// get code info size, and skip line number table
|
||||
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
|
||||
mp_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
|
||||
ip += code_info_size;
|
||||
|
||||
// bytecode prelude: state size and exception stack size; 16 bit uints
|
||||
machine_uint_t n_state = ip[0] | (ip[1] << 8);
|
||||
machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
|
||||
mp_uint_t n_state = ip[0] | (ip[1] << 8);
|
||||
mp_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
|
||||
ip += 4;
|
||||
|
||||
#if VM_DETECT_STACK_OVERFLOW
|
||||
@@ -380,7 +375,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
||||
#endif
|
||||
|
||||
// allocate state for locals and stack
|
||||
uint state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
|
||||
mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
|
||||
mp_code_state *code_state;
|
||||
if (state_size > VM_MAX_STATE_ON_STACK) {
|
||||
code_state = m_new_obj_var(mp_code_state, byte, state_size);
|
||||
@@ -411,7 +406,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
||||
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) {
|
||||
// Just check to see that we have at least 1 null object left in the state.
|
||||
bool overflow = true;
|
||||
for (uint i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) {
|
||||
if (code_state->state[i] == MP_OBJ_NULL) {
|
||||
overflow = false;
|
||||
break;
|
||||
@@ -463,12 +458,12 @@ const mp_obj_type_t mp_type_fun_bc = {
|
||||
.print = fun_bc_print,
|
||||
#endif
|
||||
.call = fun_bc_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
|
||||
uint n_def_args = 0;
|
||||
uint n_extra_args = 0;
|
||||
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
|
||||
mp_uint_t n_def_args = 0;
|
||||
mp_uint_t n_extra_args = 0;
|
||||
mp_obj_tuple_t *def_args = def_args_in;
|
||||
if (def_args != MP_OBJ_NULL) {
|
||||
assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||
@@ -498,22 +493,144 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
|
||||
return o;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* native functions */
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
typedef struct _mp_obj_fun_native_t {
|
||||
mp_obj_base_t base;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
// TODO add mp_map_t *globals
|
||||
} mp_obj_fun_native_t;
|
||||
|
||||
typedef mp_obj_t (*native_fun_0_t)();
|
||||
typedef mp_obj_t (*native_fun_1_t)(mp_obj_t);
|
||||
typedef mp_obj_t (*native_fun_2_t)(mp_obj_t, mp_obj_t);
|
||||
typedef mp_obj_t (*native_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
|
||||
|
||||
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_native_t *self = self_in;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return ((native_fun_0_t)fun)();
|
||||
|
||||
case 1:
|
||||
return ((native_fun_1_t)fun)(args[0]);
|
||||
|
||||
case 2:
|
||||
return ((native_fun_2_t)fun)(args[0], args[1]);
|
||||
|
||||
case 3:
|
||||
return ((native_fun_3_t)fun)(args[0], args[1], args[2]);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_fun_native = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_native_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data) {
|
||||
assert(0 <= n_args && n_args <= 3);
|
||||
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
|
||||
o->base.type = &mp_type_fun_native;
|
||||
o->n_args = n_args;
|
||||
o->fun_data = fun_data;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
/******************************************************************************/
|
||||
/* viper functions */
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
typedef struct _mp_obj_fun_viper_t {
|
||||
mp_obj_base_t base;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
mp_uint_t type_sig;
|
||||
} mp_obj_fun_viper_t;
|
||||
|
||||
typedef mp_uint_t (*viper_fun_0_t)();
|
||||
typedef mp_uint_t (*viper_fun_1_t)(mp_uint_t);
|
||||
typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t);
|
||||
typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
|
||||
|
||||
STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_viper_t *self = self_in;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
mp_uint_t ret;
|
||||
if (n_args == 0) {
|
||||
ret = ((viper_fun_0_t)fun)();
|
||||
} else if (n_args == 1) {
|
||||
ret = ((viper_fun_1_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2));
|
||||
} else if (n_args == 2) {
|
||||
ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4));
|
||||
} else if (n_args == 3) {
|
||||
ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4), mp_convert_obj_to_native(args[2], self->type_sig >> 6));
|
||||
} else {
|
||||
assert(0);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return mp_convert_native_to_obj(ret, self->type_sig);
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_fun_viper = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_viper_call,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig) {
|
||||
mp_obj_fun_viper_t *o = m_new_obj(mp_obj_fun_viper_t);
|
||||
o->base.type = &mp_type_fun_viper;
|
||||
o->n_args = n_args;
|
||||
o->fun_data = fun_data;
|
||||
o->type_sig = type_sig;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
/******************************************************************************/
|
||||
/* inline assembler functions */
|
||||
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
typedef struct _mp_obj_fun_asm_t {
|
||||
mp_obj_base_t base;
|
||||
int n_args;
|
||||
void *fun;
|
||||
mp_uint_t n_args;
|
||||
void *fun_data; // GC must be able to trace this pointer
|
||||
} mp_obj_fun_asm_t;
|
||||
|
||||
typedef machine_uint_t (*inline_asm_fun_0_t)();
|
||||
typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
|
||||
typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
|
||||
typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_0_t)();
|
||||
typedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t);
|
||||
typedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
|
||||
|
||||
// convert a Micro Python object to a sensible value for inline asm
|
||||
STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
// TODO for byte_array, pass pointer to the array
|
||||
if (MP_OBJ_IS_SMALL_INT(obj)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(obj);
|
||||
@@ -526,42 +643,42 @@ STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
} else if (MP_OBJ_IS_STR(obj)) {
|
||||
// pointer to the string (it's probably constant though!)
|
||||
uint l;
|
||||
return (machine_uint_t)mp_obj_str_get_data(obj, &l);
|
||||
return (mp_uint_t)mp_obj_str_get_data(obj, &l);
|
||||
} else {
|
||||
mp_obj_type_t *type = mp_obj_get_type(obj);
|
||||
if (0) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (type == &mp_type_float) {
|
||||
// convert float to int (could also pass in float registers)
|
||||
return (machine_int_t)mp_obj_float_get(obj);
|
||||
return (mp_int_t)mp_obj_float_get(obj);
|
||||
#endif
|
||||
} else if (type == &mp_type_tuple) {
|
||||
// pointer to start of tuple (could pass length, but then could use len(x) for that)
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_tuple_get(obj, &len, &items);
|
||||
return (machine_uint_t)items;
|
||||
return (mp_uint_t)items;
|
||||
} else if (type == &mp_type_list) {
|
||||
// pointer to start of list (could pass length, but then could use len(x) for that)
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_list_get(obj, &len, &items);
|
||||
return (machine_uint_t)items;
|
||||
return (mp_uint_t)items;
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) {
|
||||
// supports the buffer protocol, return a pointer to the data
|
||||
return (machine_uint_t)bufinfo.buf;
|
||||
return (mp_uint_t)bufinfo.buf;
|
||||
} else {
|
||||
// just pass along a pointer to the object
|
||||
return (machine_uint_t)obj;
|
||||
return (mp_uint_t)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert a return value from inline asm to a sensible Micro Python object
|
||||
STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
|
||||
STATIC mp_obj_t convert_val_from_inline_asm(mp_uint_t val) {
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
|
||||
@@ -570,15 +687,17 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
||||
machine_uint_t ret;
|
||||
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
|
||||
|
||||
mp_uint_t ret;
|
||||
if (n_args == 0) {
|
||||
ret = ((inline_asm_fun_0_t)self->fun)();
|
||||
ret = ((inline_asm_fun_0_t)fun)();
|
||||
} else if (n_args == 1) {
|
||||
ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
|
||||
ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0]));
|
||||
} else if (n_args == 2) {
|
||||
ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
|
||||
ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
|
||||
} else if (n_args == 3) {
|
||||
ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
|
||||
ret = ((inline_asm_fun_3_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
|
||||
} else {
|
||||
assert(0);
|
||||
ret = 0;
|
||||
@@ -591,13 +710,15 @@ STATIC const mp_obj_type_t mp_type_fun_asm = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_function,
|
||||
.call = fun_asm_call,
|
||||
.binary_op = fun_binary_op,
|
||||
.binary_op = mp_obj_fun_binary_op,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
|
||||
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data) {
|
||||
mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
|
||||
o->base.type = &mp_type_fun_asm;
|
||||
o->n_args = n_args;
|
||||
o->fun = fun;
|
||||
o->fun_data = fun_data;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
18
py/objfun.h
18
py/objfun.h
@@ -26,15 +26,15 @@
|
||||
|
||||
typedef struct _mp_obj_fun_bc_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||
machine_uint_t n_pos_args : 16; // number of arguments this function takes
|
||||
machine_uint_t n_kwonly_args : 16; // number of arguments this function takes
|
||||
machine_uint_t n_def_args : 16; // number of default arguments
|
||||
machine_uint_t has_def_kw_args : 1; // set if this function has default keyword args
|
||||
machine_uint_t takes_var_args : 1; // set if this function takes variable args
|
||||
machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
||||
const byte *bytecode; // bytecode for the function
|
||||
qstr *args; // argument names (needed to resolve positional args passed as keywords)
|
||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||
mp_uint_t n_pos_args : 16; // number of arguments this function takes
|
||||
mp_uint_t n_kwonly_args : 16; // number of arguments this function takes
|
||||
mp_uint_t n_def_args : 16; // number of default arguments
|
||||
mp_uint_t has_def_kw_args : 1; // set if this function has default keyword args
|
||||
mp_uint_t takes_var_args : 1; // set if this function takes variable args
|
||||
mp_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
||||
const byte *bytecode; // bytecode for the function
|
||||
qstr *args; // argument names (needed to resolve positional args passed as keywords)
|
||||
// the following extra_args array is allocated space to take (in order):
|
||||
// - values of positional default args (if any)
|
||||
// - a single slot for default kw args dict (if it has them)
|
||||
|
||||
@@ -59,12 +59,12 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
|
||||
|
||||
const byte *bytecode = self_fun->bytecode;
|
||||
// get code info size, and skip the line number table
|
||||
machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
|
||||
mp_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
|
||||
bytecode += code_info_size;
|
||||
|
||||
// bytecode prelude: get state size and exception stack size
|
||||
machine_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
|
||||
machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
|
||||
mp_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
|
||||
mp_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
|
||||
bytecode += 4;
|
||||
|
||||
// allocate the generator object, with room for local stack and exception stack
|
||||
|
||||
31
py/objint.c
31
py/objint.c
@@ -38,6 +38,7 @@
|
||||
#include "smallint.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "objstr.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
@@ -57,14 +58,14 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
|
||||
if (MP_OBJ_IS_INT(args[0])) {
|
||||
// already an int (small or long), just return it
|
||||
return args[0];
|
||||
} else if (MP_OBJ_IS_STR(args[0])) {
|
||||
} else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) {
|
||||
// a string, parse it
|
||||
uint l;
|
||||
const char *s = mp_obj_str_get_data(args[0], &l);
|
||||
return mp_parse_num_integer(s, l, 0);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
|
||||
return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
|
||||
return MP_OBJ_NEW_SMALL_INT((MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
|
||||
#endif
|
||||
} else {
|
||||
// try to convert to small int (eg from bool)
|
||||
@@ -85,7 +86,7 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
|
||||
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
// The size of this buffer is rather arbitrary. If it's not large
|
||||
// enough, a dynamic one will be allocated.
|
||||
char stack_buf[sizeof(machine_int_t) * 4];
|
||||
char stack_buf[sizeof(mp_int_t) * 4];
|
||||
char *buf = stack_buf;
|
||||
int buf_size = sizeof(stack_buf);
|
||||
int fmt_size;
|
||||
@@ -101,7 +102,7 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||
typedef mp_longint_impl_t fmt_int_t;
|
||||
#else
|
||||
typedef mp_small_int_t fmt_int_t;
|
||||
typedef mp_int_t fmt_int_t;
|
||||
#endif
|
||||
|
||||
STATIC const uint log_base2_floor[] = {
|
||||
@@ -145,7 +146,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
|
||||
// Not a small int.
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||
const mp_obj_int_t *self = self_in;
|
||||
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
|
||||
// Get the value to format; mp_obj_get_int truncates to mp_int_t.
|
||||
num = self->val;
|
||||
#else
|
||||
// Delegate to the implementation for the long int.
|
||||
@@ -215,6 +216,10 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
||||
|
||||
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
return mp_obj_get_int(self_in) >= 0;
|
||||
}
|
||||
@@ -241,7 +246,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
|
||||
// SMALL_INT accepts only signed numbers, of one bit less size
|
||||
// then word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -251,7 +256,7 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
@@ -259,11 +264,11 @@ mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
|
||||
@@ -285,7 +290,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_
|
||||
// true acts as 0
|
||||
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
|
||||
} else if (op == MP_BINARY_OP_MULTIPLY) {
|
||||
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
||||
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
||||
// multiply is commutative for these types, so delegate to them
|
||||
return mp_binary_op(op, rhs_in, lhs_in);
|
||||
}
|
||||
@@ -304,7 +309,7 @@ STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// convert the bytes to an integer
|
||||
machine_uint_t value = 0;
|
||||
mp_uint_t value = 0;
|
||||
for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
|
||||
value = (value << 8) | *buf;
|
||||
}
|
||||
@@ -316,7 +321,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_fro
|
||||
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, (const mp_obj_t)&int_from_bytes_fun_obj);
|
||||
|
||||
STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
|
||||
machine_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
mp_int_t val = mp_obj_int_get_checked(args[0]);
|
||||
|
||||
uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||
byte *data;
|
||||
@@ -326,7 +331,7 @@ STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
|
||||
// TODO: Support signed param
|
||||
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
|
||||
memset(data, 0, len);
|
||||
memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
|
||||
memcpy(data, &val, len < sizeof(mp_int_t) ? len : sizeof(mp_int_t));
|
||||
return mp_obj_str_builder_end(o);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
|
||||
int base, const char *prefix, char base_char, char comma);
|
||||
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *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);
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
|
||||
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||
|
||||
@@ -50,6 +50,21 @@
|
||||
#define SUFFIX ""
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
// Export value for sys.maxsize
|
||||
const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, INT_MAX};
|
||||
#endif
|
||||
|
||||
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
mp_obj_int_t *self = self_in;
|
||||
// truncate value to fit in mp_int_t, which gives the same hash as
|
||||
// small int if the value fits without truncation
|
||||
return self->val;
|
||||
}
|
||||
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
|
||||
@@ -140,14 +155,14 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
return mp_obj_new_int_from_ll(value);
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
|
||||
// SMALL_INT accepts only signed numbers, of one bit less size
|
||||
// than word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -174,7 +189,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint
|
||||
return o;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
@@ -183,7 +198,7 @@ machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
}
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
// TODO: Check overflow
|
||||
return mp_obj_int_get(self_in);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,26 @@
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
|
||||
|
||||
#if MICROPY_PY_SYS_MAXSIZE
|
||||
// Export value for sys.maxsize
|
||||
#define DIG_MASK ((1 << MPZ_DIG_SIZE) - 1)
|
||||
STATIC const mpz_dig_t maxsize_dig[MPZ_NUM_DIG_FOR_INT] = {
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
|
||||
#if (INT_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
|
||||
(INT_MAX >> MPZ_DIG_SIZE * 4) & DIG_MASK,
|
||||
// (INT_MAX >> MPZ_DIG_SIZE * 5) & DIG_MASK,
|
||||
#endif
|
||||
};
|
||||
const mp_obj_int_t mp_maxsize_obj = {
|
||||
{&mp_type_int},
|
||||
{.fixed_dig = 1, .len = MPZ_NUM_DIG_FOR_INT, .alloc = MPZ_NUM_DIG_FOR_INT, .dig = (mpz_dig_t*)maxsize_dig}
|
||||
};
|
||||
#undef DIG_MASK
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
|
||||
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
|
||||
o->base.type = &mp_type_int;
|
||||
@@ -76,6 +96,14 @@ char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_con
|
||||
return str;
|
||||
}
|
||||
|
||||
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
}
|
||||
mp_obj_int_t *self = self_in;
|
||||
return mpz_hash(&self->mpz);
|
||||
}
|
||||
|
||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
|
||||
@@ -121,8 +149,10 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) {
|
||||
return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
|
||||
return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
// delegate to generic function to check for extra cases
|
||||
@@ -195,8 +225,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_INPLACE_LSHIFT:
|
||||
case MP_BINARY_OP_RSHIFT:
|
||||
case MP_BINARY_OP_INPLACE_RSHIFT: {
|
||||
// TODO check conversion overflow
|
||||
machine_int_t irhs = mpz_as_int(zrhs);
|
||||
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"));
|
||||
}
|
||||
@@ -239,7 +268,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int(machine_int_t value) {
|
||||
mp_obj_t mp_obj_new_int(mp_int_t value) {
|
||||
if (MP_SMALL_INT_FITS(value)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
@@ -252,7 +281,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
|
||||
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
|
||||
// SMALL_INT accepts only signed numbers, of one bit less size
|
||||
// than word size, which totals 2 bits less for unsigned numbers.
|
||||
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
|
||||
@@ -268,21 +297,22 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint
|
||||
return o;
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get(mp_const_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
const mp_obj_int_t *self = self_in;
|
||||
return mpz_as_int(&self->mpz);
|
||||
// TODO this is a hack until we remove mp_obj_int_get function entirely
|
||||
return mpz_hash(&self->mpz);
|
||||
}
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
} else {
|
||||
const mp_obj_int_t *self = self_in;
|
||||
machine_int_t value;
|
||||
mp_int_t value;
|
||||
if (mpz_as_int_checked(&self->mpz, &value)) {
|
||||
return value;
|
||||
} else {
|
||||
|
||||
@@ -127,10 +127,13 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
return o;
|
||||
}
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
machine_int_t n;
|
||||
mp_int_t n;
|
||||
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
if (n < 0) {
|
||||
n = 0;
|
||||
}
|
||||
mp_obj_list_t *s = list_new(o->len * n);
|
||||
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
||||
return s;
|
||||
@@ -488,7 +491,7 @@ void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
typedef struct _mp_obj_list_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_list_t *list;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_list_it_t;
|
||||
|
||||
mp_obj_t list_it_iternext(mp_obj_t self_in) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
typedef struct _mp_obj_list_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t alloc;
|
||||
machine_uint_t len;
|
||||
mp_uint_t alloc;
|
||||
mp_uint_t len;
|
||||
mp_obj_t *items;
|
||||
} mp_obj_list_t;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
typedef struct _mp_obj_map_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t n_iters;
|
||||
mp_uint_t n_iters;
|
||||
mp_obj_t fun;
|
||||
mp_obj_t iters[];
|
||||
} mp_obj_map_t;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -39,9 +40,9 @@
|
||||
typedef struct _mp_obj_range_it_t {
|
||||
mp_obj_base_t base;
|
||||
// TODO make these values generic objects or something
|
||||
machine_int_t cur;
|
||||
machine_int_t stop;
|
||||
machine_int_t step;
|
||||
mp_int_t cur;
|
||||
mp_int_t stop;
|
||||
mp_int_t step;
|
||||
} mp_obj_range_it_t;
|
||||
|
||||
STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) {
|
||||
@@ -77,11 +78,21 @@ mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step) {
|
||||
typedef struct _mp_obj_range_t {
|
||||
mp_obj_base_t base;
|
||||
// TODO make these values generic objects or something
|
||||
machine_int_t start;
|
||||
machine_int_t stop;
|
||||
machine_int_t step;
|
||||
mp_int_t start;
|
||||
mp_int_t stop;
|
||||
mp_int_t step;
|
||||
} mp_obj_range_t;
|
||||
|
||||
STATIC void range_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_range_t *self = self_in;
|
||||
print(env, "range(%d, %d", self->start, self->stop);
|
||||
if (self->step == 1) {
|
||||
print(env, ")");
|
||||
} else {
|
||||
print(env, ", %d)", self->step);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 3, false);
|
||||
|
||||
@@ -96,6 +107,7 @@ STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
|
||||
o->start = mp_obj_get_int(args[0]);
|
||||
o->stop = mp_obj_get_int(args[1]);
|
||||
if (n_args == 3) {
|
||||
// TODO check step is non-zero
|
||||
o->step = mp_obj_get_int(args[2]);
|
||||
}
|
||||
}
|
||||
@@ -103,6 +115,55 @@ STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC mp_int_t range_len(mp_obj_range_t *self) {
|
||||
// When computing length, need to take into account step!=1 and step<0.
|
||||
mp_int_t len = self->stop - self->start + self->step;
|
||||
if (self->step > 0) {
|
||||
len -= 1;
|
||||
} else {
|
||||
len += 1;
|
||||
}
|
||||
len = len / self->step;
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t range_unary_op(int op, mp_obj_t self_in) {
|
||||
mp_obj_range_t *self = self_in;
|
||||
mp_int_t len = range_len(self);
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(len > 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
mp_obj_range_t *self = self_in;
|
||||
mp_int_t len = range_len(self);
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
mp_bound_slice_t slice;
|
||||
mp_seq_get_fast_slice_indexes(len, index, &slice);
|
||||
mp_obj_range_t *o = m_new_obj(mp_obj_range_t);
|
||||
o->base.type = &mp_type_range;
|
||||
o->start = slice.start;
|
||||
o->stop = slice.stop;
|
||||
o->step = slice.step;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
uint index_val = mp_get_index(self->base.type, len, index, false);
|
||||
return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);
|
||||
} else {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
|
||||
mp_obj_range_t *o = o_in;
|
||||
return mp_obj_new_range_iterator(o->start, o->stop, o->step);
|
||||
@@ -111,6 +172,9 @@ STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
|
||||
const mp_obj_type_t mp_type_range = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_range,
|
||||
.print = range_print,
|
||||
.make_new = range_make_new,
|
||||
.unary_op = range_unary_op,
|
||||
.subscr = range_subscr,
|
||||
.getiter = range_getiter,
|
||||
};
|
||||
|
||||
74
py/objreversed.c
Normal file
74
py/objreversed.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
typedef struct _mp_obj_reversed_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t seq; // sequence object that we are reversing
|
||||
mp_uint_t cur_index; // current index, plus 1; 0=no more, 1=last one (index 0)
|
||||
} mp_obj_reversed_t;
|
||||
|
||||
STATIC mp_obj_t reversed_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t);
|
||||
o->base.type = &mp_type_reversed;
|
||||
o->seq = args[0];
|
||||
o->cur_index = mp_obj_get_int(mp_obj_len(args[0])); // start at the end of the sequence
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed));
|
||||
mp_obj_reversed_t *self = self_in;
|
||||
|
||||
// "raise" stop iteration if we are at the end (the start) of the sequence
|
||||
if (self->cur_index == 0) {
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
|
||||
// pre-decrement and index sequence
|
||||
self->cur_index -= 1;
|
||||
return mp_obj_subscr(self->seq, MP_OBJ_NEW_SMALL_INT(self->cur_index), MP_OBJ_SENTINEL);
|
||||
}
|
||||
|
||||
const mp_obj_type_t mp_type_reversed = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_reversed,
|
||||
.make_new = reversed_make_new,
|
||||
.getiter = mp_identity,
|
||||
.iternext = reversed_iternext,
|
||||
};
|
||||
@@ -47,7 +47,7 @@ typedef struct _mp_obj_set_t {
|
||||
typedef struct _mp_obj_set_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_set_t *set;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_set_it_t;
|
||||
|
||||
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in);
|
||||
@@ -160,10 +160,10 @@ const mp_obj_type_t mp_type_set_it = {
|
||||
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set_it));
|
||||
mp_obj_set_it_t *self = self_in;
|
||||
machine_uint_t max = self->set->set.alloc;
|
||||
mp_uint_t max = self->set->set.alloc;
|
||||
mp_set_t *set = &self->set->set;
|
||||
|
||||
for (machine_uint_t i = self->cur; i < max; i++) {
|
||||
for (mp_uint_t i = self->cur; i < max; i++) {
|
||||
if (MP_SET_SLOT_IS_FILLED(set, i)) {
|
||||
self->cur = i + 1;
|
||||
return set->table[i];
|
||||
@@ -476,7 +476,7 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) {
|
||||
mp_obj_set_t *self = self_in;
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used);
|
||||
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used);
|
||||
default: return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
265
py/objstr.c
265
py/objstr.c
@@ -32,6 +32,7 @@
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "unicode.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -43,28 +44,16 @@
|
||||
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict);
|
||||
const mp_obj_t mp_const_empty_bytes;
|
||||
|
||||
// use this macro to extract the string hash
|
||||
#define GET_STR_HASH(str_obj_in, str_hash) uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
|
||||
|
||||
// use this macro to extract the string length
|
||||
#define GET_STR_LEN(str_obj_in, str_len) uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; }
|
||||
|
||||
// use this macro to extract the string data and length
|
||||
#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
|
||||
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
|
||||
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
|
||||
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
|
||||
STATIC NORETURN void arg_type_mixup();
|
||||
|
||||
STATIC bool is_str_or_bytes(mp_obj_t o) {
|
||||
return MP_OBJ_IS_STR(o) || MP_OBJ_IS_TYPE(o, &mp_type_bytes);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* str */
|
||||
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
|
||||
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
const byte *str_data, uint str_len, bool is_bytes) {
|
||||
// this escapes characters, but it will be very slow to print (calling print many times)
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
@@ -85,7 +74,10 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
print(env, "\\%c", quote_char);
|
||||
} else if (*s == '\\') {
|
||||
print(env, "\\\\");
|
||||
} else if (32 <= *s && *s <= 126) {
|
||||
} else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
|
||||
// In strings, anything which is not ascii control character
|
||||
// is printed as is, this includes characters in range 0x80-0xff
|
||||
// (which can be non-Latin letters, etc.)
|
||||
print(env, "%c", *s);
|
||||
} else if (*s == '\n') {
|
||||
print(env, "\\n");
|
||||
@@ -109,7 +101,7 @@ STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||
if (is_bytes) {
|
||||
print(env, "b");
|
||||
}
|
||||
mp_str_print_quoted(print, env, str_data, str_len);
|
||||
mp_str_print_quoted(print, env, str_data, str_len, is_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,9 +222,9 @@ wrong_args:
|
||||
|
||||
// like strstr but with specified length and allows \0 bytes
|
||||
// TODO replace with something more efficient/standard
|
||||
STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, const byte *needle, machine_uint_t nlen, machine_int_t direction) {
|
||||
STATIC const byte *find_subbytes(const byte *haystack, mp_uint_t hlen, const byte *needle, mp_uint_t nlen, mp_int_t direction) {
|
||||
if (hlen >= nlen) {
|
||||
machine_uint_t str_index, str_index_end;
|
||||
mp_uint_t str_index, str_index_end;
|
||||
if (direction > 0) {
|
||||
str_index = 0;
|
||||
str_index_end = hlen - nlen;
|
||||
@@ -255,7 +247,10 @@ STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, cons
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
// Note: this function is used to check if an object is a str or bytes, which
|
||||
// works because both those types use it as their binary_op method. Revisit
|
||||
// MP_OBJ_IS_STR_OR_BYTES if this fact changes.
|
||||
mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);
|
||||
mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
|
||||
mp_obj_type_t *rhs_type = mp_obj_get_type(rhs_in);
|
||||
@@ -294,10 +289,16 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
break;
|
||||
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
if (!MP_OBJ_IS_SMALL_INT(rhs_in)) {
|
||||
mp_int_t n;
|
||||
if (!mp_obj_get_int_maybe(rhs_in, &n)) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs_in);
|
||||
if (n <= 0) {
|
||||
if (lhs_type == &mp_type_str) {
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
byte *data;
|
||||
mp_obj_t s = mp_obj_str_builder_start(lhs_type, lhs_len * n, &data);
|
||||
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data);
|
||||
@@ -348,7 +349,17 @@ uncomparable:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
// objstrunicode defines own version
|
||||
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
|
||||
mp_obj_t index, bool is_slice) {
|
||||
mp_uint_t index_val = mp_get_index(type, self_len, index, is_slice);
|
||||
return self_data + index_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This is used for both bytes and 8-bit strings. This is not used for unicode strings.
|
||||
STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(self_in);
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
@@ -363,11 +374,12 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
|
||||
}
|
||||
#endif
|
||||
uint index_val = mp_get_index(type, self_len, index, false);
|
||||
if (type == &mp_type_bytes) {
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self_data[index_val]);
|
||||
mp_uint_t index_val = mp_get_index(type, self_len, index, false);
|
||||
// If we have unicode enabled the type will always be bytes, so take the short cut.
|
||||
if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
|
||||
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
|
||||
} else {
|
||||
return mp_obj_new_str((char*)self_data + index_val, 1, true);
|
||||
return mp_obj_new_str((char*)&self_data[index_val], 1, true);
|
||||
}
|
||||
} else {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
@@ -375,7 +387,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
|
||||
assert(is_str_or_bytes(self_in));
|
||||
assert(MP_OBJ_IS_STR_OR_BYTES(self_in));
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
|
||||
|
||||
// get separation string
|
||||
@@ -430,7 +442,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
|
||||
|
||||
STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
machine_int_t splits = -1;
|
||||
mp_int_t splits = -1;
|
||||
mp_obj_t sep = mp_const_none;
|
||||
if (n_args > 1) {
|
||||
sep = args[1];
|
||||
@@ -467,6 +479,9 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
} else {
|
||||
// sep given
|
||||
if (mp_obj_get_type(sep) != self_type) {
|
||||
arg_type_mixup();
|
||||
}
|
||||
|
||||
uint sep_len;
|
||||
const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
|
||||
@@ -510,8 +525,8 @@ STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_t sep = args[1];
|
||||
GET_STR_DATA_LEN(args[0], s, len);
|
||||
|
||||
machine_int_t splits = mp_obj_get_int(args[2]);
|
||||
machine_int_t org_splits = splits;
|
||||
mp_int_t splits = mp_obj_get_int(args[2]);
|
||||
mp_int_t org_splits = splits;
|
||||
// Preallocate list to the max expected # of elements, as we
|
||||
// will fill it from the end.
|
||||
mp_obj_list_t *res = mp_obj_new_list(splits + 1, NULL);
|
||||
@@ -561,8 +576,8 @@ STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) {
|
||||
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, mp_int_t direction, bool is_index) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
assert(2 <= n_args && n_args <= 4);
|
||||
assert(MP_OBJ_IS_STR(args[0]));
|
||||
assert(MP_OBJ_IS_STR(args[1]));
|
||||
@@ -570,16 +585,16 @@ STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t dire
|
||||
GET_STR_DATA_LEN(args[0], haystack, haystack_len);
|
||||
GET_STR_DATA_LEN(args[1], needle, needle_len);
|
||||
|
||||
machine_uint_t start = 0;
|
||||
machine_uint_t end = haystack_len;
|
||||
const byte *start = haystack;
|
||||
const byte *end = haystack + haystack_len;
|
||||
if (n_args >= 3 && args[2] != mp_const_none) {
|
||||
start = mp_get_index(&mp_type_str, haystack_len, args[2], true);
|
||||
start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
|
||||
}
|
||||
if (n_args >= 4 && args[3] != mp_const_none) {
|
||||
end = mp_get_index(&mp_type_str, haystack_len, args[3], true);
|
||||
end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
|
||||
}
|
||||
|
||||
const byte *p = find_subbytes(haystack + start, end - start, needle, needle_len, direction);
|
||||
const byte *p = find_subbytes(start, end - start, needle, needle_len, direction);
|
||||
if (p == NULL) {
|
||||
// not found
|
||||
if (is_index) {
|
||||
@@ -589,6 +604,11 @@ STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t dire
|
||||
}
|
||||
} else {
|
||||
// found
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
if (self_type == &mp_type_str) {
|
||||
return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p));
|
||||
}
|
||||
#endif
|
||||
return MP_OBJ_NEW_SMALL_INT(p - haystack);
|
||||
}
|
||||
}
|
||||
@@ -611,16 +631,17 @@ STATIC mp_obj_t str_rindex(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
// TODO: (Much) more variety in args
|
||||
STATIC mp_obj_t str_startswith(uint n_args, const mp_obj_t *args) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
GET_STR_DATA_LEN(args[0], str, str_len);
|
||||
GET_STR_DATA_LEN(args[1], prefix, prefix_len);
|
||||
uint index_val = 0;
|
||||
const byte *start = str;
|
||||
if (n_args > 2) {
|
||||
index_val = mp_get_index(&mp_type_str, str_len, args[2], true);
|
||||
start = str_index_to_ptr(self_type, str, str_len, args[2], true);
|
||||
}
|
||||
if (prefix_len + index_val > str_len) {
|
||||
if (prefix_len + (start - str) > str_len) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return MP_BOOL(memcmp(str + index_val, prefix, prefix_len) == 0);
|
||||
return MP_BOOL(memcmp(start, prefix, prefix_len) == 0);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_endswith(uint n_args, const mp_obj_t *args) {
|
||||
@@ -638,7 +659,7 @@ enum { LSTRIP, RSTRIP, STRIP };
|
||||
|
||||
STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
assert(1 <= n_args && n_args <= 2);
|
||||
assert(is_str_or_bytes(args[0]));
|
||||
assert(MP_OBJ_IS_STR_OR_BYTES(args[0]));
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
|
||||
const byte *chars_to_del;
|
||||
@@ -659,16 +680,16 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
|
||||
GET_STR_DATA_LEN(args[0], orig_str, orig_str_len);
|
||||
|
||||
machine_uint_t first_good_char_pos = 0;
|
||||
mp_uint_t first_good_char_pos = 0;
|
||||
bool first_good_char_pos_set = false;
|
||||
machine_uint_t last_good_char_pos = 0;
|
||||
machine_uint_t i = 0;
|
||||
machine_int_t delta = 1;
|
||||
mp_uint_t last_good_char_pos = 0;
|
||||
mp_uint_t i = 0;
|
||||
mp_int_t delta = 1;
|
||||
if (type == RSTRIP) {
|
||||
i = orig_str_len - 1;
|
||||
delta = -1;
|
||||
}
|
||||
for (machine_uint_t len = orig_str_len; len > 0; len--) {
|
||||
for (mp_uint_t len = orig_str_len; len > 0; len--) {
|
||||
if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) {
|
||||
if (!first_good_char_pos_set) {
|
||||
first_good_char_pos_set = true;
|
||||
@@ -694,7 +715,7 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
|
||||
|
||||
assert(last_good_char_pos >= first_good_char_pos);
|
||||
//+1 to accomodate the last character
|
||||
machine_uint_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
|
||||
mp_uint_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
|
||||
if (stripped_len == orig_str_len) {
|
||||
// If nothing was stripped, don't bother to dup original string
|
||||
// TODO: watch out for this case when we'll get to bytearray.strip()
|
||||
@@ -757,7 +778,7 @@ static mp_obj_t arg_as_int(mp_obj_t arg) {
|
||||
|
||||
// TODO: Needs a way to construct an mpz integer from a float
|
||||
|
||||
mp_small_int_t num = mp_obj_get_float(arg);
|
||||
mp_int_t num = mp_obj_get_float(arg);
|
||||
return MP_OBJ_NEW_SMALL_INT(num);
|
||||
}
|
||||
#endif
|
||||
@@ -1318,7 +1339,7 @@ not_enough_args:
|
||||
STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_STR(args[0]));
|
||||
|
||||
machine_int_t max_rep = -1;
|
||||
mp_int_t max_rep = -1;
|
||||
if (n_args == 4) {
|
||||
max_rep = mp_obj_get_int(args[3]);
|
||||
if (max_rep == 0) {
|
||||
@@ -1359,11 +1380,11 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
|
||||
// first pass computes the required length of the replaced string
|
||||
// second pass does the replacements
|
||||
for (;;) {
|
||||
machine_uint_t replaced_str_index = 0;
|
||||
machine_uint_t num_replacements_done = 0;
|
||||
mp_uint_t replaced_str_index = 0;
|
||||
mp_uint_t num_replacements_done = 0;
|
||||
const byte *old_occurrence;
|
||||
const byte *offset_ptr = str;
|
||||
machine_uint_t str_len_remain = str_len;
|
||||
mp_uint_t str_len_remain = str_len;
|
||||
if (old_len == 0) {
|
||||
// if old_str is empty, copy new_str to start of replaced string
|
||||
// copy the replacement string
|
||||
@@ -1418,6 +1439,7 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
assert(2 <= n_args && n_args <= 4);
|
||||
assert(MP_OBJ_IS_STR(args[0]));
|
||||
assert(MP_OBJ_IS_STR(args[1]));
|
||||
@@ -1425,34 +1447,36 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
|
||||
GET_STR_DATA_LEN(args[0], haystack, haystack_len);
|
||||
GET_STR_DATA_LEN(args[1], needle, needle_len);
|
||||
|
||||
machine_uint_t start = 0;
|
||||
machine_uint_t end = haystack_len;
|
||||
const byte *start = haystack;
|
||||
const byte *end = haystack + haystack_len;
|
||||
if (n_args >= 3 && args[2] != mp_const_none) {
|
||||
start = mp_get_index(&mp_type_str, haystack_len, args[2], true);
|
||||
start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
|
||||
}
|
||||
if (n_args >= 4 && args[3] != mp_const_none) {
|
||||
end = mp_get_index(&mp_type_str, haystack_len, args[3], true);
|
||||
end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
|
||||
}
|
||||
|
||||
// if needle_len is zero then we count each gap between characters as an occurrence
|
||||
if (needle_len == 0) {
|
||||
return MP_OBJ_NEW_SMALL_INT(end - start + 1);
|
||||
return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1);
|
||||
}
|
||||
|
||||
// count the occurrences
|
||||
machine_int_t num_occurrences = 0;
|
||||
for (machine_uint_t haystack_index = start; haystack_index + needle_len <= end; haystack_index++) {
|
||||
if (memcmp(&haystack[haystack_index], needle, needle_len) == 0) {
|
||||
mp_int_t num_occurrences = 0;
|
||||
for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) {
|
||||
if (memcmp(haystack_ptr, needle, needle_len) == 0) {
|
||||
num_occurrences++;
|
||||
haystack_index += needle_len - 1;
|
||||
haystack_ptr += needle_len;
|
||||
} else {
|
||||
haystack_ptr = utf8_next_char(haystack_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(num_occurrences);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t direction) {
|
||||
if (!is_str_or_bytes(self_in)) {
|
||||
STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, mp_int_t direction) {
|
||||
if (!MP_OBJ_IS_STR_OR_BYTES(self_in)) {
|
||||
assert(0);
|
||||
}
|
||||
mp_obj_type_t *self_type = mp_obj_get_type(self_in);
|
||||
@@ -1477,7 +1501,7 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di
|
||||
|
||||
const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction);
|
||||
if (position_ptr != NULL) {
|
||||
machine_uint_t position = position_ptr - str;
|
||||
mp_uint_t position = position_ptr - str;
|
||||
result[0] = mp_obj_new_str_of_type(self_type, str, position);
|
||||
result[1] = arg;
|
||||
result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);
|
||||
@@ -1595,7 +1619,7 @@ STATIC mp_obj_t str_encode(uint n_args, const mp_obj_t *args) {
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) {
|
||||
if (flags == MP_BUFFER_READ) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
bufinfo->buf = (void*)str_data;
|
||||
@@ -1612,38 +1636,45 @@ STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
|
||||
}
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
|
||||
#endif
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
|
||||
|
||||
STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decode), (mp_obj_t)&bytes_decode_obj },
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
// If we have separate unicode type, then here we have methods only
|
||||
// for bytes type, and it should not have encode() methods. Otherwise,
|
||||
// we have non-compliant-but-practical bytestring type, which shares
|
||||
// method table with bytes, so they both have encode() and decode()
|
||||
// methods (which should do type checking at runtime).
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj },
|
||||
#endif
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
|
||||
@@ -1673,17 +1704,19 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
|
||||
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
const mp_obj_type_t mp_type_str = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_str,
|
||||
.print = str_print,
|
||||
.make_new = str_make_new,
|
||||
.binary_op = str_binary_op,
|
||||
.subscr = str_subscr,
|
||||
.binary_op = mp_obj_str_binary_op,
|
||||
.subscr = bytes_subscr,
|
||||
.getiter = mp_obj_new_str_iterator,
|
||||
.buffer_p = { .get_buffer = str_get_buffer },
|
||||
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&str_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
// Reuses most of methods from str
|
||||
const mp_obj_type_t mp_type_bytes = {
|
||||
@@ -1691,10 +1724,10 @@ const mp_obj_type_t mp_type_bytes = {
|
||||
.name = MP_QSTR_bytes,
|
||||
.print = str_print,
|
||||
.make_new = bytes_make_new,
|
||||
.binary_op = str_binary_op,
|
||||
.subscr = str_subscr,
|
||||
.binary_op = mp_obj_str_binary_op,
|
||||
.subscr = bytes_subscr,
|
||||
.getiter = mp_obj_new_bytes_iterator,
|
||||
.buffer_p = { .get_buffer = str_get_buffer },
|
||||
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&str_locals_dict,
|
||||
};
|
||||
|
||||
@@ -1721,6 +1754,16 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len) {
|
||||
mp_obj_str_t *o = o_in;
|
||||
o->data = m_renew(byte, (byte*)o->data, o->len + 1, len + 1);
|
||||
o->len = len;
|
||||
o->hash = qstr_compute_hash(o->data, o->len);
|
||||
byte *p = (byte*)o->data;
|
||||
p[o->len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len) {
|
||||
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
|
||||
o->base.type = type;
|
||||
@@ -1833,7 +1876,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) {
|
||||
}
|
||||
|
||||
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len) {
|
||||
if (is_str_or_bytes(self_in)) {
|
||||
if (MP_OBJ_IS_STR_OR_BYTES(self_in)) {
|
||||
GET_STR_DATA_LEN(self_in, s, l);
|
||||
*len = l;
|
||||
return (const char*)s;
|
||||
@@ -1848,9 +1891,10 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len) {
|
||||
typedef struct _mp_obj_str_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t str;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_str_it_t;
|
||||
|
||||
#if !MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
|
||||
mp_obj_str_it_t *self = self_in;
|
||||
GET_STR_DATA_LEN(self->str, str, len);
|
||||
@@ -1870,11 +1914,20 @@ STATIC const mp_obj_type_t mp_type_str_it = {
|
||||
.iternext = str_it_iternext,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
|
||||
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
|
||||
o->base.type = &mp_type_str_it;
|
||||
o->str = str;
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) {
|
||||
mp_obj_str_it_t *self = self_in;
|
||||
GET_STR_DATA_LEN(self->str, str, len);
|
||||
if (self->cur < len) {
|
||||
mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT((mp_small_int_t)str[self->cur]);
|
||||
mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]);
|
||||
self->cur += 1;
|
||||
return o_out;
|
||||
} else {
|
||||
@@ -1889,14 +1942,6 @@ STATIC const mp_obj_type_t mp_type_bytes_it = {
|
||||
.iternext = bytes_it_iternext,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
|
||||
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
|
||||
o->base.type = &mp_type_str_it;
|
||||
o->str = str;
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str) {
|
||||
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
|
||||
o->base.type = &mp_type_bytes_it;
|
||||
|
||||
53
py/objstr.h
53
py/objstr.h
@@ -26,14 +26,61 @@
|
||||
|
||||
typedef struct _mp_obj_str_t {
|
||||
mp_obj_base_t base;
|
||||
// XXX here we assume the hash size is 16 bits (it is at the moment; see qstr.c)
|
||||
machine_uint_t hash : 16;
|
||||
mp_uint_t hash;
|
||||
// len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte
|
||||
machine_uint_t len : 16;
|
||||
mp_uint_t len;
|
||||
const byte *data;
|
||||
} mp_obj_str_t;
|
||||
|
||||
#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str};
|
||||
|
||||
// use this macro to extract the string hash
|
||||
#define GET_STR_HASH(str_obj_in, str_hash) \
|
||||
uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
|
||||
|
||||
// use this macro to extract the string length
|
||||
#define GET_STR_LEN(str_obj_in, str_len) \
|
||||
uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; }
|
||||
|
||||
// use this macro to extract the string data and length
|
||||
#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \
|
||||
const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
|
||||
{ str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \
|
||||
else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
|
||||
|
||||
mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len);
|
||||
|
||||
mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags);
|
||||
|
||||
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
|
||||
mp_obj_t index, bool is_slice);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_encode_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_find_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_index_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_join_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_split_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_strip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_format_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_replace_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_count_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_partition_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_lower_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_upper_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(str_islower_obj);
|
||||
|
||||
@@ -43,7 +43,7 @@ typedef struct _mp_obj_stringio_t {
|
||||
mp_obj_base_t base;
|
||||
vstr_t *vstr;
|
||||
// StringIO has single pointer used for both reading and writing
|
||||
machine_uint_t pos;
|
||||
mp_uint_t pos;
|
||||
} mp_obj_stringio_t;
|
||||
|
||||
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
@@ -51,9 +51,9 @@ STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
|
||||
}
|
||||
|
||||
STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
machine_uint_t remaining = o->vstr->len - o->pos;
|
||||
mp_uint_t remaining = o->vstr->len - o->pos;
|
||||
if (size > remaining) {
|
||||
size = remaining;
|
||||
}
|
||||
@@ -62,9 +62,9 @@ STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_stringio_t *o = o_in;
|
||||
machine_uint_t remaining = o->vstr->alloc - o->pos;
|
||||
mp_uint_t remaining = o->vstr->alloc - o->pos;
|
||||
if (size > remaining) {
|
||||
// Take all what's already allocated...
|
||||
o->vstr->len = o->vstr->alloc;
|
||||
@@ -137,12 +137,12 @@ STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
|
||||
STATIC const mp_stream_p_t stringio_stream_p = {
|
||||
.read = stringio_read,
|
||||
.write = stringio_write,
|
||||
.is_text = true,
|
||||
};
|
||||
|
||||
STATIC const mp_stream_p_t bytesio_stream_p = {
|
||||
.read = stringio_read,
|
||||
.write = stringio_write,
|
||||
.is_bytes = true,
|
||||
};
|
||||
|
||||
const mp_obj_type_t mp_type_stringio = {
|
||||
|
||||
359
py/objstrunicode.c
Normal file
359
py/objstrunicode.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "pfenv.h"
|
||||
#include "objstr.h"
|
||||
#include "objlist.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
|
||||
|
||||
/******************************************************************************/
|
||||
/* str */
|
||||
|
||||
STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
|
||||
// this escapes characters, but it will be very slow to print (calling print many times)
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
|
||||
if (*s == '\'') {
|
||||
has_single_quote = true;
|
||||
} else if (*s == '"') {
|
||||
has_double_quote = true;
|
||||
}
|
||||
}
|
||||
int quote_char = '\'';
|
||||
if (has_single_quote && !has_double_quote) {
|
||||
quote_char = '"';
|
||||
}
|
||||
print(env, "%c", quote_char);
|
||||
const byte *s = str_data, *top = str_data + str_len;
|
||||
while (s < top) {
|
||||
unichar ch;
|
||||
ch = utf8_get_char(s);
|
||||
s = utf8_next_char(s);
|
||||
if (ch == quote_char) {
|
||||
print(env, "\\%c", quote_char);
|
||||
} else if (ch == '\\') {
|
||||
print(env, "\\\\");
|
||||
} else if (32 <= ch && ch <= 126) {
|
||||
print(env, "%c", ch);
|
||||
} else if (ch == '\n') {
|
||||
print(env, "\\n");
|
||||
} else if (ch == '\r') {
|
||||
print(env, "\\r");
|
||||
} else if (ch == '\t') {
|
||||
print(env, "\\t");
|
||||
} else if (ch < 0x100) {
|
||||
print(env, "\\x%02x", ch);
|
||||
} else if (ch < 0x10000) {
|
||||
print(env, "\\u%04x", ch);
|
||||
} else {
|
||||
print(env, "\\U%08x", ch);
|
||||
}
|
||||
}
|
||||
print(env, "%c", quote_char);
|
||||
}
|
||||
|
||||
STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
if (kind == PRINT_STR) {
|
||||
print(env, "%.*s", str_len, str_data);
|
||||
} else {
|
||||
uni_print_quoted(print, env, str_data, str_len);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uni_unary_op(int op, mp_obj_t self_in) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_BOOL:
|
||||
return MP_BOOL(str_len != 0);
|
||||
case MP_UNARY_OP_LEN:
|
||||
return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len));
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (n_kw != 0) {
|
||||
mp_arg_error_unimpl_kw();
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (n_args) {
|
||||
case 0:
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
|
||||
case 1:
|
||||
{
|
||||
vstr_t *vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
// TODO: validate 2nd/3rd args
|
||||
if (!MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected"));
|
||||
}
|
||||
GET_STR_DATA_LEN(args[0], str_data, str_len);
|
||||
GET_STR_HASH(args[0], str_hash);
|
||||
mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len);
|
||||
o->data = str_data;
|
||||
o->hash = str_hash;
|
||||
return o;
|
||||
}
|
||||
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments"));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or
|
||||
// be capped to the first/last character of the string, depending on is_slice.
|
||||
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
|
||||
mp_obj_t index, bool is_slice) {
|
||||
mp_int_t i;
|
||||
// Copied from mp_get_index; I don't want bounds checking, just give me
|
||||
// the integer as-is. (I can't bounds-check without scanning the whole
|
||||
// string; an out-of-bounds index will be caught in the loops below.)
|
||||
if (MP_OBJ_IS_SMALL_INT(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index)));
|
||||
}
|
||||
const byte *s, *top = self_data + self_len;
|
||||
if (i < 0)
|
||||
{
|
||||
// Negative indexing is performed by counting from the end of the string.
|
||||
for (s = top - 1; i; --s) {
|
||||
if (s < self_data) {
|
||||
if (is_slice) {
|
||||
return self_data;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
|
||||
}
|
||||
if (!UTF8_IS_CONT(*s)) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
++s;
|
||||
} else if (!i) {
|
||||
return self_data; // Shortcut - str[0] is its base pointer
|
||||
} else {
|
||||
// Positive indexing, correspondingly, counts from the start of the string.
|
||||
// It's assumed that negative indexing will generally be used with small
|
||||
// absolute values (eg str[-1], not str[-1000000]), which means it'll be
|
||||
// more efficient this way.
|
||||
for (s = self_data; true; ++s) {
|
||||
if (s >= top) {
|
||||
if (is_slice) {
|
||||
return top;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
|
||||
}
|
||||
while (UTF8_IS_CONT(*s)) {
|
||||
++s;
|
||||
}
|
||||
if (!i--) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_type_t *type = mp_obj_get_type(self_in);
|
||||
GET_STR_DATA_LEN(self_in, self_data, self_len);
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
|
||||
mp_obj_t ostart, ostop, ostep;
|
||||
mp_obj_slice_get(index, &ostart, &ostop, &ostep);
|
||||
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
"only slices with step=1 (aka None) are supported"));
|
||||
}
|
||||
|
||||
if (type == &mp_type_bytes) {
|
||||
mp_int_t start = 0, stop = self_len;
|
||||
if (ostart != mp_const_none) {
|
||||
start = MP_OBJ_SMALL_INT_VALUE(ostart);
|
||||
if (start < 0) {
|
||||
start = self_len + start;
|
||||
}
|
||||
}
|
||||
if (ostop != mp_const_none) {
|
||||
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
|
||||
if (stop < 0) {
|
||||
stop = self_len + stop;
|
||||
}
|
||||
}
|
||||
return mp_obj_new_str_of_type(type, self_data + start, stop - start);
|
||||
}
|
||||
const byte *pstart, *pstop;
|
||||
if (ostart != mp_const_none) {
|
||||
pstart = str_index_to_ptr(type, self_data, self_len, ostart, true);
|
||||
} else {
|
||||
pstart = self_data;
|
||||
}
|
||||
if (ostop != mp_const_none) {
|
||||
// pstop will point just after the stop character. This depends on
|
||||
// the \0 at the end of the string.
|
||||
pstop = str_index_to_ptr(type, self_data, self_len, ostop, true);
|
||||
} else {
|
||||
pstop = self_data + self_len;
|
||||
}
|
||||
if (pstop < pstart) {
|
||||
return MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
}
|
||||
return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart);
|
||||
}
|
||||
#endif
|
||||
if (type == &mp_type_bytes) {
|
||||
uint index_val = mp_get_index(type, self_len, index, false);
|
||||
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
|
||||
}
|
||||
const byte *s = str_index_to_ptr(type, self_data, self_len, index, false);
|
||||
int len = 1;
|
||||
if (UTF8_IS_NONASCII(*s)) {
|
||||
// Count the number of 1 bits (after the first)
|
||||
for (char mask = 0x40; *s & mask; mask >>= 1) {
|
||||
++len;
|
||||
}
|
||||
}
|
||||
return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string
|
||||
} else {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t str_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&str_index_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rindex), (mp_obj_t)&str_rindex_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rsplit), (mp_obj_t)&str_rsplit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_endswith), (mp_obj_t)&str_endswith_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_lstrip), (mp_obj_t)&str_lstrip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rstrip), (mp_obj_t)&str_rstrip_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&str_format_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&str_replace_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&str_count_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_partition), (mp_obj_t)&str_partition_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_type_str = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_str,
|
||||
.print = uni_print,
|
||||
.make_new = str_make_new,
|
||||
.unary_op = uni_unary_op,
|
||||
.binary_op = mp_obj_str_binary_op,
|
||||
.subscr = str_subscr,
|
||||
.getiter = mp_obj_new_str_iterator,
|
||||
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
|
||||
.locals_dict = (mp_obj_t)&str_locals_dict,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/* str iterator */
|
||||
|
||||
typedef struct _mp_obj_str_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t str;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_str_it_t;
|
||||
|
||||
STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
|
||||
mp_obj_str_it_t *self = self_in;
|
||||
GET_STR_DATA_LEN(self->str, str, len);
|
||||
if (self->cur < len) {
|
||||
const byte *cur = str + self->cur;
|
||||
const byte *end = utf8_next_char(str + self->cur);
|
||||
mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true);
|
||||
self->cur += end - cur;
|
||||
return o_out;
|
||||
} else {
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_str_it = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_iterator,
|
||||
.getiter = mp_identity,
|
||||
.iternext = str_it_iternext,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
|
||||
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
|
||||
o->base.type = &mp_type_str_it;
|
||||
o->str = str;
|
||||
o->cur = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
@@ -137,10 +137,13 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
return s;
|
||||
}
|
||||
case MP_BINARY_OP_MULTIPLY: {
|
||||
if (!MP_OBJ_IS_SMALL_INT(rhs)) {
|
||||
mp_int_t n;
|
||||
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs);
|
||||
if (n <= 0) {
|
||||
return mp_const_empty_tuple;
|
||||
}
|
||||
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
|
||||
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
||||
return s;
|
||||
@@ -252,11 +255,11 @@ void mp_obj_tuple_del(mp_obj_t self_in) {
|
||||
m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);
|
||||
}
|
||||
|
||||
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple));
|
||||
mp_obj_tuple_t *self = self_in;
|
||||
// start hash with pointer to empty tuple, to make it fairly unique
|
||||
machine_int_t hash = (machine_int_t)mp_const_empty_tuple;
|
||||
mp_int_t hash = (mp_int_t)mp_const_empty_tuple;
|
||||
for (uint i = 0; i < self->len; i++) {
|
||||
hash += mp_obj_hash(self->items[i]);
|
||||
}
|
||||
@@ -269,7 +272,7 @@ machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
|
||||
typedef struct _mp_obj_tuple_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_tuple_t *tuple;
|
||||
machine_uint_t cur;
|
||||
mp_uint_t cur;
|
||||
} mp_obj_tuple_it_t;
|
||||
|
||||
STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
typedef struct _mp_obj_tuple_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uint_t len;
|
||||
mp_uint_t len;
|
||||
mp_obj_t items[];
|
||||
} mp_obj_tuple_t;
|
||||
|
||||
|
||||
27
py/objtype.c
27
py/objtype.c
@@ -46,6 +46,8 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
|
||||
/******************************************************************************/
|
||||
// instance object
|
||||
|
||||
@@ -101,7 +103,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
|
||||
struct class_lookup_data {
|
||||
mp_obj_instance_t *obj;
|
||||
qstr attr;
|
||||
machine_uint_t meth_offset;
|
||||
mp_uint_t meth_offset;
|
||||
mp_obj_t *dest;
|
||||
bool is_type;
|
||||
};
|
||||
@@ -379,11 +381,12 @@ STATIC const qstr binary_op_method_name[] = {
|
||||
MP_BINARY_OP_INPLACE_MODULO,
|
||||
MP_BINARY_OP_INPLACE_POWER,*/
|
||||
[MP_BINARY_OP_LESS] = MP_QSTR___lt__,
|
||||
/*MP_BINARY_OP_MORE,
|
||||
MP_BINARY_OP_EQUAL,
|
||||
MP_BINARY_OP_LESS_EQUAL,
|
||||
MP_BINARY_OP_MORE_EQUAL,
|
||||
MP_BINARY_OP_NOT_EQUAL,
|
||||
[MP_BINARY_OP_MORE] = MP_QSTR___gt__,
|
||||
[MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
|
||||
[MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
|
||||
[MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
|
||||
/*
|
||||
MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
|
||||
*/
|
||||
[MP_BINARY_OP_IN] = MP_QSTR___contains__,
|
||||
/*
|
||||
@@ -749,6 +752,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
|
||||
assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
|
||||
|
||||
// TODO might need to make a copy of locals_dict; at least that's how CPython does it
|
||||
|
||||
// Basic validation of base classes
|
||||
uint len;
|
||||
mp_obj_t *items;
|
||||
@@ -783,6 +788,16 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"));
|
||||
}
|
||||
|
||||
mp_map_t *locals_map = mp_obj_dict_get_map(o->locals_dict);
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
// __new__ slot exists; check if it is a function
|
||||
if (MP_OBJ_IS_FUN(elem->value)) {
|
||||
// __new__ is a function, wrap it in a staticmethod decorator
|
||||
elem->value = static_class_method_make_new((mp_obj_t)&mp_type_staticmethod, 1, 0, &elem->value);
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
88
py/parse.c
88
py/parse.c
@@ -30,8 +30,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parsenumbase.h"
|
||||
@@ -109,20 +109,20 @@ STATIC const rule_t *rules[] = {
|
||||
};
|
||||
|
||||
typedef struct _rule_stack_t {
|
||||
unsigned int src_line : 24;
|
||||
unsigned int rule_id : 8;
|
||||
int32_t arg_i; // what should be the size and signedness?
|
||||
mp_uint_t src_line : 24;
|
||||
mp_uint_t rule_id : 8;
|
||||
mp_uint_t arg_i : 32; // what should the bit-size be?
|
||||
} rule_stack_t;
|
||||
|
||||
typedef struct _parser_t {
|
||||
bool had_memory_error;
|
||||
|
||||
uint rule_stack_alloc;
|
||||
uint rule_stack_top;
|
||||
mp_uint_t rule_stack_alloc;
|
||||
mp_uint_t rule_stack_top;
|
||||
rule_stack_t *rule_stack;
|
||||
|
||||
uint result_stack_alloc;
|
||||
uint result_stack_top;
|
||||
mp_uint_t result_stack_alloc;
|
||||
mp_uint_t result_stack_top;
|
||||
mp_parse_node_t *result_stack;
|
||||
|
||||
mp_lexer_t *lexer;
|
||||
@@ -132,7 +132,7 @@ STATIC inline void memory_error(parser_t *parser) {
|
||||
parser->had_memory_error = true;
|
||||
}
|
||||
|
||||
STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) {
|
||||
STATIC void push_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t arg_i) {
|
||||
if (parser->had_memory_error) {
|
||||
return;
|
||||
}
|
||||
@@ -151,14 +151,14 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar
|
||||
rs->arg_i = arg_i;
|
||||
}
|
||||
|
||||
STATIC void push_rule_from_arg(parser_t *parser, uint arg) {
|
||||
STATIC void push_rule_from_arg(parser_t *parser, mp_uint_t arg) {
|
||||
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
|
||||
uint rule_id = arg & RULE_ARG_ARG_MASK;
|
||||
mp_uint_t rule_id = arg & RULE_ARG_ARG_MASK;
|
||||
assert(rule_id < RULE_maximum_number_of);
|
||||
push_rule(parser, mp_lexer_cur(parser->lexer)->src_line, rules[rule_id], 0);
|
||||
}
|
||||
|
||||
STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) {
|
||||
STATIC void pop_rule(parser_t *parser, const rule_t **rule, mp_uint_t *arg_i, mp_uint_t *src_line) {
|
||||
assert(!parser->had_memory_error);
|
||||
parser->rule_stack_top -= 1;
|
||||
*rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
|
||||
@@ -166,7 +166,7 @@ STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *s
|
||||
*src_line = parser->rule_stack[parser->rule_stack_top].src_line;
|
||||
}
|
||||
|
||||
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
|
||||
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg) {
|
||||
if (kind == MP_PARSE_NODE_SMALL_INT) {
|
||||
return (mp_parse_node_t)(kind | (arg << 1));
|
||||
}
|
||||
@@ -176,8 +176,8 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
|
||||
void mp_parse_node_free(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
|
||||
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
uint rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
|
||||
mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
mp_uint_t rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
|
||||
if (rule_id == RULE_string) {
|
||||
return;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ void mp_parse_node_free(mp_parse_node_t pn) {
|
||||
if (adjust) {
|
||||
n--;
|
||||
}
|
||||
for (uint i = 0; i < n; i++) {
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_free(pns->nodes[i]);
|
||||
}
|
||||
if (adjust) {
|
||||
@@ -196,22 +196,22 @@ void mp_parse_node_free(mp_parse_node_t pn) {
|
||||
}
|
||||
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
for (int i = 0; i < indent; i++) {
|
||||
for (mp_uint_t i = 0; i < indent; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
printf("NULL\n");
|
||||
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
printf("int(" INT_FMT ")\n", arg);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break;
|
||||
@@ -227,13 +227,13 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_string) {
|
||||
printf("literal str(%.*s)\n", (int)pns->nodes[1], (char*)pns->nodes[0]);
|
||||
} else {
|
||||
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
#ifdef USE_RULE_NAME
|
||||
printf("%s(%d) (n=%d)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
printf("%s(" UINT_FMT ") (n=" UINT_FMT ")\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
#else
|
||||
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
printf("rule(" UINT_FMT ") (n=" UINT_FMT ")\n", (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
|
||||
#endif
|
||||
for (uint i = 0; i < n; i++) {
|
||||
for (mp_uint_t i = 0; i < n; i++) {
|
||||
mp_parse_node_print(pns->nodes[i], indent + 2);
|
||||
}
|
||||
}
|
||||
@@ -244,7 +244,7 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
|
||||
/*
|
||||
STATIC void result_stack_show(parser_t *parser) {
|
||||
printf("result stack, most recent first\n");
|
||||
for (int i = parser->result_stack_top - 1; i >= 0; i--) {
|
||||
for (mp_int_t i = parser->result_stack_top - 1; i >= 0; i--) {
|
||||
mp_parse_node_print(parser->result_stack[i], 0);
|
||||
}
|
||||
}
|
||||
@@ -258,7 +258,7 @@ STATIC mp_parse_node_t pop_result(parser_t *parser) {
|
||||
return parser->result_stack[--parser->result_stack_top];
|
||||
}
|
||||
|
||||
STATIC mp_parse_node_t peek_result(parser_t *parser, int pos) {
|
||||
STATIC mp_parse_node_t peek_result(parser_t *parser, mp_uint_t pos) {
|
||||
if (parser->had_memory_error) {
|
||||
return MP_PARSE_NODE_NULL;
|
||||
}
|
||||
@@ -282,7 +282,7 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {
|
||||
parser->result_stack[parser->result_stack_top++] = pn;
|
||||
}
|
||||
|
||||
STATIC void push_result_string(parser_t *parser, int src_line, const char *str, uint len) {
|
||||
STATIC void push_result_string(parser_t *parser, mp_uint_t src_line, const char *str, mp_uint_t len) {
|
||||
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, 2);
|
||||
if (pn == NULL) {
|
||||
memory_error(parser);
|
||||
@@ -292,7 +292,7 @@ STATIC void push_result_string(parser_t *parser, int src_line, const char *str,
|
||||
pn->kind_num_nodes = RULE_string | (2 << 8);
|
||||
char *p = m_new(char, len);
|
||||
memcpy(p, str, len);
|
||||
pn->nodes[0] = (machine_int_t)p;
|
||||
pn->nodes[0] = (mp_int_t)p;
|
||||
pn->nodes[1] = len;
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
}
|
||||
@@ -305,14 +305,14 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
} else if (tok->kind == MP_TOKEN_NUMBER) {
|
||||
bool dec = false;
|
||||
bool small_int = true;
|
||||
machine_int_t int_val = 0;
|
||||
int len = tok->len;
|
||||
mp_int_t int_val = 0;
|
||||
mp_uint_t len = tok->len;
|
||||
const char *str = tok->str;
|
||||
int base = 0;
|
||||
int i = mp_parse_num_base(str, len, &base);
|
||||
mp_uint_t base = 0;
|
||||
mp_uint_t i = mp_parse_num_base(str, len, &base);
|
||||
bool overflow = false;
|
||||
for (; i < len; i++) {
|
||||
int dig;
|
||||
mp_uint_t dig;
|
||||
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
|
||||
dig = str[i] - '0';
|
||||
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
|
||||
@@ -369,7 +369,7 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
|
||||
push_result_node(parser, pn);
|
||||
}
|
||||
|
||||
STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) {
|
||||
STATIC void push_result_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t num_args) {
|
||||
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args);
|
||||
if (pn == NULL) {
|
||||
memory_error(parser);
|
||||
@@ -377,7 +377,7 @@ STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule,
|
||||
}
|
||||
pn->source_line = src_line;
|
||||
pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8);
|
||||
for (int i = num_args; i > 0; i--) {
|
||||
for (mp_uint_t i = num_args; i > 0; i--) {
|
||||
pn->nodes[i - 1] = pop_result(parser);
|
||||
}
|
||||
push_result_node(parser, (mp_parse_node_t)pn);
|
||||
@@ -407,7 +407,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
}
|
||||
|
||||
// work out the top-level rule to use, and push it on the stack
|
||||
int top_level_rule;
|
||||
mp_uint_t top_level_rule;
|
||||
switch (input_kind) {
|
||||
case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break;
|
||||
case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
|
||||
@@ -417,8 +417,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
|
||||
// parse!
|
||||
|
||||
uint n, i; // state for the current rule
|
||||
uint rule_src_line; // source line for the first token matched by the current rule
|
||||
mp_uint_t n, i; // state for the current rule
|
||||
mp_uint_t rule_src_line; // source line for the first token matched by the current rule
|
||||
bool backtrack = false;
|
||||
const rule_t *rule = NULL;
|
||||
mp_token_kind_t tok_kind;
|
||||
@@ -541,7 +541,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
// count number of arguments for the parse_node
|
||||
i = 0;
|
||||
emit_rule = false;
|
||||
for (int x = 0; x < n; ++x) {
|
||||
for (mp_uint_t x = 0; x < n; ++x) {
|
||||
if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
|
||||
tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
|
||||
if (tok_kind >= MP_TOKEN_NAME) {
|
||||
@@ -578,7 +578,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
// never emit these rules if they have only 1 argument
|
||||
// NOTE: can't put atom_paren here because we need it to distinguisg, for example, [a,b] from [(a,b)]
|
||||
// TODO possibly put varargslist_name, varargslist_equal here as well
|
||||
if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef) {
|
||||
if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef || rule->rule_id == RULE_funcdefrettype) {
|
||||
emit_rule = false;
|
||||
}
|
||||
|
||||
@@ -589,8 +589,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
i += 1;
|
||||
}
|
||||
|
||||
int num_not_nil = 0;
|
||||
for (int x = 0; x < i; ++x) {
|
||||
mp_uint_t num_not_nil = 0;
|
||||
for (mp_uint_t x = 0; x < i; ++x) {
|
||||
if (peek_result(&parser, x) != MP_PARSE_NODE_NULL) {
|
||||
num_not_nil += 1;
|
||||
}
|
||||
@@ -605,7 +605,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
} else if (num_not_nil == 1) {
|
||||
// single result, leave it on stack
|
||||
mp_parse_node_t pn = MP_PARSE_NODE_NULL;
|
||||
for (int x = 0; x < i; ++x) {
|
||||
for (mp_uint_t x = 0; x < i; ++x) {
|
||||
mp_parse_node_t pn2 = pop_result(&parser);
|
||||
if (pn2 != MP_PARSE_NODE_NULL) {
|
||||
pn = pn2;
|
||||
@@ -653,7 +653,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
|
||||
}
|
||||
} else {
|
||||
for (;;) {
|
||||
uint arg = rule->arg[i & 1 & n];
|
||||
mp_uint_t arg = rule->arg[i & 1 & n];
|
||||
switch (arg & RULE_ARG_KIND_MASK) {
|
||||
case RULE_ARG_TOK:
|
||||
if (mp_lexer_is_kind(lex, arg & RULE_ARG_ARG_MASK)) {
|
||||
|
||||
10
py/parse.h
10
py/parse.h
@@ -46,7 +46,7 @@ struct _mp_lexer_t;
|
||||
#define MP_PARSE_NODE_BYTES (0x12)
|
||||
#define MP_PARSE_NODE_TOKEN (0x16)
|
||||
|
||||
typedef machine_uint_t mp_parse_node_t; // must be pointer size
|
||||
typedef mp_uint_t mp_parse_node_t; // must be pointer size
|
||||
|
||||
typedef struct _mp_parse_node_struct_t {
|
||||
uint32_t source_line; // line number in source file
|
||||
@@ -69,15 +69,15 @@ typedef struct _mp_parse_node_struct_t {
|
||||
|
||||
#define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x1f)
|
||||
// TODO should probably have int and uint versions of this macro
|
||||
#define MP_PARSE_NODE_LEAF_ARG(pn) (((machine_uint_t)(pn)) >> 5)
|
||||
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((machine_int_t)(pn)) >> 1)
|
||||
#define MP_PARSE_NODE_LEAF_ARG(pn) (((mp_uint_t)(pn)) >> 5)
|
||||
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(pn)) >> 1)
|
||||
#define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff)
|
||||
#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8)
|
||||
|
||||
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg);
|
||||
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg);
|
||||
void mp_parse_node_free(mp_parse_node_t pn);
|
||||
|
||||
void mp_parse_node_print(mp_parse_node_t pn, int indent);
|
||||
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent);
|
||||
|
||||
typedef enum {
|
||||
MP_PARSE_SINGLE_INPUT,
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -43,7 +43,7 @@
|
||||
#define STR_INVALID_SYNTAX "invalid syntax"
|
||||
|
||||
void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_kind) {
|
||||
printf(" File \"%s\", line %d, column %d\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
|
||||
printf(" File \"%s\", line " UINT_FMT ", column " UINT_FMT "\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
|
||||
switch (parse_error_kind) {
|
||||
case MP_PARSE_ERROR_MEMORY:
|
||||
printf("MemoryError: %s\n", STR_MEMORY);
|
||||
|
||||
@@ -27,21 +27,23 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "nlr.h"
|
||||
#include "obj.h"
|
||||
#include "parsenumbase.h"
|
||||
#include "parsenum.h"
|
||||
#include "smallint.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
const char *restrict top = str + len;
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str_, mp_uint_t len, mp_uint_t base) {
|
||||
const byte *restrict str = (const byte *)str_;
|
||||
const byte *restrict top = str + len;
|
||||
bool neg = false;
|
||||
mp_obj_t ret_val;
|
||||
|
||||
@@ -65,14 +67,14 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
|
||||
}
|
||||
|
||||
// parse optional base prefix
|
||||
str += mp_parse_num_base(str, top - str, &base);
|
||||
str += mp_parse_num_base((const char*)str, top - str, &base);
|
||||
|
||||
// string should be an integer number
|
||||
machine_int_t int_val = 0;
|
||||
const char *restrict str_val_start = str;
|
||||
mp_int_t int_val = 0;
|
||||
const byte *restrict str_val_start = str;
|
||||
for (; str < top; str++) {
|
||||
// get next digit as a value
|
||||
int dig = *str;
|
||||
mp_uint_t dig = *str;
|
||||
if (unichar_isdigit(dig) && dig - '0' < base) {
|
||||
// 0-9 digit
|
||||
dig = dig - '0';
|
||||
@@ -129,9 +131,9 @@ have_ret_val:
|
||||
overflow:
|
||||
// reparse using long int
|
||||
{
|
||||
const char *s2 = str_val_start;
|
||||
const char *s2 = (const char*)str_val_start;
|
||||
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
|
||||
str = s2;
|
||||
str = (const byte*)s2;
|
||||
goto have_ret_val;
|
||||
}
|
||||
|
||||
@@ -139,11 +141,13 @@ value_error:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str));
|
||||
}
|
||||
|
||||
#define PARSE_DEC_IN_INTG (1)
|
||||
#define PARSE_DEC_IN_FRAC (2)
|
||||
#define PARSE_DEC_IN_EXP (3)
|
||||
typedef enum {
|
||||
PARSE_DEC_IN_INTG,
|
||||
PARSE_DEC_IN_FRAC,
|
||||
PARSE_DEC_IN_EXP,
|
||||
} parse_dec_in_t;
|
||||
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
const char *top = str + len;
|
||||
mp_float_t dec_val = 0;
|
||||
@@ -185,12 +189,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
|
||||
}
|
||||
} else {
|
||||
// string should be a decimal number
|
||||
int in = PARSE_DEC_IN_INTG;
|
||||
parse_dec_in_t in = PARSE_DEC_IN_INTG;
|
||||
bool exp_neg = false;
|
||||
int exp_val = 0;
|
||||
int exp_extra = 0;
|
||||
mp_int_t exp_val = 0;
|
||||
mp_int_t exp_extra = 0;
|
||||
for (; str < top; str++) {
|
||||
int dig = *str;
|
||||
mp_uint_t dig = *str;
|
||||
if ('0' <= dig && dig <= '9') {
|
||||
dig -= '0';
|
||||
if (in == PARSE_DEC_IN_EXP) {
|
||||
@@ -251,10 +255,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
|
||||
}
|
||||
|
||||
// return the object
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
if (imag) {
|
||||
return mp_obj_new_complex(0, dec_val);
|
||||
} else if (force_complex) {
|
||||
return mp_obj_new_complex(dec_val, 0);
|
||||
#else
|
||||
if (imag || force_complex) {
|
||||
mp_not_implemented("complex values not supported");
|
||||
#endif
|
||||
} else {
|
||||
return mp_obj_new_float(dec_val);
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base);
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex);
|
||||
mp_obj_t mp_parse_num_integer(const char *restrict str, mp_uint_t len, mp_uint_t base);
|
||||
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex);
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "parsenumbase.h"
|
||||
|
||||
// find real radix base, and strip preceding '0x', '0o' and '0b'
|
||||
// puts base in *base, and returns number of bytes to skip the prefix
|
||||
int mp_parse_num_base(const char *str, uint len, int *base) {
|
||||
const char *p = str;
|
||||
int c = *(p++);
|
||||
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base) {
|
||||
const byte *p = (const byte*)str;
|
||||
unichar c = *(p++);
|
||||
if ((*base == 0 || *base == 16) && c == '0') {
|
||||
c = *(p++);
|
||||
if ((c | 32) == 'x') {
|
||||
@@ -63,6 +63,5 @@ int mp_parse_num_base(const char *str, uint len, int *base) {
|
||||
}
|
||||
p--;
|
||||
}
|
||||
return p - str;
|
||||
return p - (const byte*)str;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int mp_parse_num_base(const char *str, uint len, int *base);
|
||||
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base);
|
||||
|
||||
10
py/pfenv.c
10
py/pfenv.c
@@ -27,8 +27,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "mpz.h"
|
||||
@@ -111,14 +111,14 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
|
||||
|
||||
// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null
|
||||
// We can use 16 characters for 32-bit and 32 characters for 64-bit
|
||||
#define INT_BUF_SIZE (sizeof(machine_int_t) * 4)
|
||||
#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
|
||||
|
||||
// This function is used by stmhal port to implement printf.
|
||||
// It needs to be a separate function to pfenv_print_mp_int, since converting to a mp_int looses the MSB.
|
||||
int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
|
||||
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
|
||||
char sign = 0;
|
||||
if (sgn) {
|
||||
if ((machine_int_t)x < 0) {
|
||||
if ((mp_int_t)x < 0) {
|
||||
sign = '-';
|
||||
x = -x;
|
||||
} else if (flags & PF_FLAG_SHOW_SIGN) {
|
||||
@@ -232,7 +232,7 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
|
||||
|
||||
// The size of this buffer is rather arbitrary. If it's not large
|
||||
// enough, a dynamic one will be allocated.
|
||||
char stack_buf[sizeof(machine_int_t) * 4];
|
||||
char stack_buf[sizeof(mp_int_t) * 4];
|
||||
char *buf = stack_buf;
|
||||
int buf_size = sizeof(stack_buf);
|
||||
int fmt_size = 0;
|
||||
|
||||
@@ -44,8 +44,11 @@ typedef struct _pfenv_t {
|
||||
void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len);
|
||||
|
||||
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width);
|
||||
int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
|
||||
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
|
||||
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
|
||||
#endif
|
||||
|
||||
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
|
||||
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);
|
||||
|
||||
199
py/pfenv_printf.c
Normal file
199
py/pfenv_printf.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "pfenv.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include "formatfloat.h"
|
||||
#endif
|
||||
|
||||
int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args) {
|
||||
int chrs = 0;
|
||||
for (;;) {
|
||||
{
|
||||
const char *f = fmt;
|
||||
while (*f != '\0' && *f != '%') {
|
||||
++f; // XXX UTF8 advance char
|
||||
}
|
||||
if (f > fmt) {
|
||||
pfenv->print_strn(pfenv->data, fmt, f - fmt);
|
||||
chrs += f - fmt;
|
||||
fmt = f;
|
||||
}
|
||||
}
|
||||
|
||||
if (*fmt == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
// move past % character
|
||||
++fmt;
|
||||
|
||||
// parse flags, if they exist
|
||||
int flags = 0;
|
||||
char fill = ' ';
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
|
||||
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
|
||||
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
|
||||
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
|
||||
else if (*fmt == '0') {
|
||||
flags |= PF_FLAG_PAD_AFTER_SIGN;
|
||||
fill = '0';
|
||||
} else break;
|
||||
++fmt;
|
||||
}
|
||||
|
||||
// parse width, if it exists
|
||||
int width = 0;
|
||||
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
|
||||
width = width * 10 + *fmt - '0';
|
||||
}
|
||||
|
||||
// parse precision, if it exists
|
||||
int prec = -1;
|
||||
if (*fmt == '.') {
|
||||
++fmt;
|
||||
if (*fmt == '*') {
|
||||
++fmt;
|
||||
prec = va_arg(args, int);
|
||||
} else {
|
||||
prec = 0;
|
||||
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
|
||||
prec = prec * 10 + *fmt - '0';
|
||||
}
|
||||
}
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// parse long specifiers (current not used)
|
||||
//bool long_arg = false;
|
||||
if (*fmt == 'l') {
|
||||
++fmt;
|
||||
//long_arg = true;
|
||||
}
|
||||
|
||||
if (*fmt == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*fmt) {
|
||||
case 'b':
|
||||
if (va_arg(args, int)) {
|
||||
chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width);
|
||||
} else {
|
||||
chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
char str = va_arg(args, int);
|
||||
chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width);
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
const char *str = va_arg(args, const char*);
|
||||
if (str) {
|
||||
if (prec < 0) {
|
||||
prec = strlen(str);
|
||||
}
|
||||
chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width);
|
||||
} else {
|
||||
chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width);
|
||||
break;
|
||||
case 'd':
|
||||
chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width);
|
||||
break;
|
||||
case 'x':
|
||||
case 'p': // ?
|
||||
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width);
|
||||
break;
|
||||
case 'X':
|
||||
case 'P': // ?
|
||||
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width);
|
||||
break;
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
mp_float_t f = va_arg(args, double);
|
||||
chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec);
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
// Currently pfenv_print_float uses snprintf, but snprintf
|
||||
// itself may be implemented in terms of pfenv_vprintf() for
|
||||
// some ports. So, for extra caution, this case is handled
|
||||
// with assert below. Note that currently ports which
|
||||
// use MICROPY_FLOAT_IMPL_DOUBLE, don't call pfenv_vprintf()
|
||||
// with float format specifier at all.
|
||||
// TODO: resolve this completely
|
||||
assert(0);
|
||||
//#error Calling pfenv_print_float with double not supported from within printf
|
||||
#else
|
||||
#error Unknown MICROPY FLOAT IMPL
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
pfenv->print_strn(pfenv->data, fmt, 1);
|
||||
chrs += 1;
|
||||
break;
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
return chrs;
|
||||
}
|
||||
|
||||
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = pfenv_vprintf(pfenv, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
13
py/py.mk
13
py/py.mk
@@ -38,11 +38,15 @@ PY_O_BASENAME = \
|
||||
asmthumb.o \
|
||||
emitnthumb.o \
|
||||
emitinlinethumb.o \
|
||||
asmarm.o \
|
||||
emitnarm.o \
|
||||
formatfloat.o \
|
||||
parsenumbase.o \
|
||||
parsenum.o \
|
||||
emitglue.o \
|
||||
runtime.o \
|
||||
nativeglue.o \
|
||||
stackctrl.o \
|
||||
argcheck.o \
|
||||
map.o \
|
||||
obj.o \
|
||||
@@ -71,9 +75,11 @@ PY_O_BASENAME = \
|
||||
objnone.o \
|
||||
objnamedtuple.o \
|
||||
objrange.o \
|
||||
objreversed.o \
|
||||
objset.o \
|
||||
objslice.o \
|
||||
objstr.o \
|
||||
objstrunicode.o \
|
||||
objstringio.o \
|
||||
objtuple.o \
|
||||
objtype.o \
|
||||
@@ -100,6 +106,9 @@ PY_O_BASENAME = \
|
||||
repl.o \
|
||||
smallint.o \
|
||||
pfenv.o \
|
||||
pfenv_printf.o \
|
||||
../extmod/moductypes.o \
|
||||
../extmod/modzlibd.o \
|
||||
|
||||
# prepend the build destination prefix to the py object files
|
||||
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
|
||||
@@ -139,6 +148,10 @@ $(PY_BUILD)/emitnthumb.o: CFLAGS += -DN_THUMB
|
||||
$(PY_BUILD)/emitnthumb.o: py/emitnative.c
|
||||
$(call compile_c)
|
||||
|
||||
$(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM
|
||||
$(PY_BUILD)/emitnarm.o: py/emitnative.c
|
||||
$(call compile_c)
|
||||
|
||||
# optimising gc for speed; 5ms down to 4ms on pybv2
|
||||
$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)
|
||||
|
||||
|
||||
16
py/qstr.c
16
py/qstr.c
@@ -27,8 +27,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
|
||||
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
|
||||
@@ -55,9 +55,9 @@
|
||||
#define Q_GET_DATA(q) ((q) + 4)
|
||||
|
||||
// this must match the equivalent function in makeqstrdata.py
|
||||
machine_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
mp_uint_t qstr_compute_hash(const byte *data, uint len) {
|
||||
// djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html
|
||||
machine_uint_t hash = 5381;
|
||||
mp_uint_t hash = 5381;
|
||||
for (const byte *top = data + len; data < top; data++) {
|
||||
hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data
|
||||
}
|
||||
@@ -132,7 +132,7 @@ STATIC qstr qstr_add(const byte *q_ptr) {
|
||||
|
||||
qstr qstr_find_strn(const char *str, uint str_len) {
|
||||
// work out hash of str
|
||||
machine_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
|
||||
mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
|
||||
|
||||
// search pools for the data
|
||||
for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
|
||||
@@ -154,7 +154,7 @@ qstr qstr_from_str(const char *str) {
|
||||
qstr qstr_from_strn(const char *str, uint len) {
|
||||
qstr q = qstr_find_strn(str, len);
|
||||
if (q == 0) {
|
||||
machine_uint_t hash = qstr_compute_hash((const byte*)str, len);
|
||||
mp_uint_t hash = qstr_compute_hash((const byte*)str, len);
|
||||
byte *q_ptr = m_new(byte, 4 + len + 1);
|
||||
q_ptr[0] = hash;
|
||||
q_ptr[1] = hash >> 8;
|
||||
@@ -178,8 +178,8 @@ byte *qstr_build_start(uint len, byte **q_ptr) {
|
||||
qstr qstr_build_end(byte *q_ptr) {
|
||||
qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
|
||||
if (q == 0) {
|
||||
machine_uint_t len = Q_GET_LENGTH(q_ptr);
|
||||
machine_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
|
||||
mp_uint_t len = Q_GET_LENGTH(q_ptr);
|
||||
mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
|
||||
q_ptr[0] = hash;
|
||||
q_ptr[1] = hash >> 8;
|
||||
q_ptr[4 + len] = '\0';
|
||||
@@ -190,7 +190,7 @@ qstr qstr_build_end(byte *q_ptr) {
|
||||
return q;
|
||||
}
|
||||
|
||||
machine_uint_t qstr_hash(qstr q) {
|
||||
mp_uint_t qstr_hash(qstr q) {
|
||||
return Q_GET_HASH(find_qstr(q));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user